Compare commits

..

41 Commits

Author SHA1 Message Date
Weblate
14f9a75a73 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Aitzol Garmendia <aitzolgarmendia@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translation: Servarr/Prowlarr
2023-12-21 02:34:36 +02:00
Weblate
ed17d91a7b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: ηg <jonas.konrath@icloud.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/de/
Translation: Servarr/Prowlarr
2023-12-19 20:02:09 +02:00
Bogdan
f54280b888 Bump version to 1.11.3 2023-12-17 15:53:28 +02:00
Bogdan
7890ef6f9d Remove invalid Turkish translations 2023-12-17 04:01:35 +02:00
Weblate
df8e4e5acb Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: lifeisfreedom048 <koyuncu.ozgur@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/tr/
Translation: Servarr/Prowlarr
2023-12-17 04:00:13 +02:00
Agneev Mukherjee
1b36951879 Enable browser navigation buttons for PWA
(cherry picked from commit da9a60691f363323565a293ed9eaeb6349ceccb6)
2023-12-16 15:44:25 +02:00
Weblate
d8d5170ab8 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Menno Liefstingh <mennoliefstingh@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translation: Servarr/Prowlarr
2023-12-15 16:43:07 +02:00
Bogdan
a443a87603 Fixed: (AvistaZ) Disable pagination and implement MST formula 2023-12-14 20:37:31 +02:00
Weblate
df18ee77e7 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: ROSERAT Ugo <roserat.ugo@gmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Co-authored-by: SHUAI.W <x@ousui.org>
Co-authored-by: matiasba <matiasabarros@hotmail.com>
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/lv/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2023-12-14 14:20:36 +02:00
Bogdan
426159b452 Fixed: (RetroFlix) Remove unrelated results 2023-12-13 21:41:13 +02:00
Bogdan
8704bef69a Update year format in titles for RED/OPS 2023-12-13 19:49:54 +02:00
Bogdan
0f1b01adab Log invalid torrent files contents as info 2023-12-12 16:53:06 +02:00
Qstick
4dbf5aa9f4 Fixed: Correctly handle Migration when PG Host has ".db"
(cherry picked from commit 97ee24507f4306e3b62c3d00cd3ade6a09d1b957)
2023-12-12 15:49:54 +02:00
Bogdan
e1264d7cda Implement DatabaseConnectionInfo
Co-authored-by: Qstick <qstick@gmail.com>
2023-12-12 15:49:50 +02:00
Bogdan
d4bbb2e14a Fixed: (FL/BHD/IPT) Filter releases by query 2023-12-10 20:06:33 +02:00
Servarr
a2395dccb5 Automated API Docs update 2023-12-10 16:08:08 +02:00
Bogdan
df89450428 New: External links for search results 2023-12-10 16:02:24 +02:00
Bogdan
7b5e1f40ba Bump version to 1.11.2 2023-12-10 13:44:44 +02:00
Bogdan
fe142b8a1c Fixed: (IPTorrents) Parse size column using index by name 2023-12-09 23:22:33 +02:00
Weblate
8c7f73ed16 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Jurriaan Den Toonder <jur.den.toonder@gmail.com>
Co-authored-by: RicardoVelaC <ricardovelac@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/nl/
Translation: Servarr/Prowlarr
2023-12-08 16:02:46 +02:00
Weblate
a4ae800603 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Augusto Poletti <augustpolet@gmail.com>
Co-authored-by: Dominika Matějková <dominika.matejkova@outlook.cz>
Co-authored-by: VisoTC <szlytlyt@outlook.com>
Co-authored-by: 米大饭 <1246333567@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/zh_CN/
Translation: Servarr/Prowlarr
2023-12-06 16:01:59 +02:00
Bogdan
e5d7a21714 New: (Discord) Add size grab field and improve field selection 2023-12-06 10:24:08 +02:00
Bogdan
67355ec07b Fixed: (aro.lol) Removed, site has shutdown 2023-12-05 14:00:02 +02:00
Bogdan
43d56f6817 New: (NorBits) Add FreeLeech Only option 2023-12-04 15:58:10 +02:00
Bogdan
515f4dff8b New: (NorBits) Login with 2FA support 2023-12-04 15:46:15 +02:00
Bogdan
c3aa377ed5 Fixed: (PTP) Parse half leech 2023-12-04 10:41:29 +02:00
Mark McDowall
fbc3c09094 Always validate Custom Script path
(cherry picked from commit c922cc5dc617dd776d4523cbf62376821c5a4ad9)
2023-12-03 20:38:54 +02:00
Maksym Ivanchenko
b88f8e5fde Fixed: (Toloka) Support RAW search (#1944) 2023-12-03 09:37:39 +02:00
Bogdan
aaf4c73c83 Bump version to 1.11.1 2023-12-03 08:46:25 +02:00
Bogdan
7c38ec2baa Fixed: (AvistaZ) Improve message for failed logins 2023-12-02 12:07:40 +02:00
Bogdan
dcfdd49119 Rollback YamlDotNet 2023-12-02 11:30:59 +02:00
Weblate
badb9dee61 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Appoxo <appoxo@appoxo.de>
Co-authored-by: David Molero <contact@dolvem.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Patatra <patrice.chevreau@gmail.com>
Co-authored-by: Zalhera <tobias.bechen@gmail.com>
Co-authored-by: liimee <git.taaa@fedora.email>
Co-authored-by: resi23 <x-resistant-x@gmx.de>
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/id/
Translate-URL: https://translate.servarr.com/projects/servarr/prowlarr/pt_BR/
Translation: Servarr/Prowlarr
2023-12-01 04:03:11 +02:00
Bogdan
12ca705556 Fixed: (AvistaZ) Increase rate limit and use workaround for Retry-After in auth 2023-11-30 01:57:32 +02:00
Bogdan
a0d0e3e232 Fixed: (OPS) Use canUseToken for download links when using Use Freeleech Tokens 2023-11-29 08:22:17 +02:00
Bogdan
e12cd68772 Fixed: (RED/OPS) Add log score to release titles 2023-11-29 08:18:24 +02:00
Bogdan
9dc117191e Minor cleanup for BTN 2023-11-28 09:22:13 +02:00
Bogdan
fdaca64d60 Fixed: (BTN) Add MST, indexer flags and parse IMDb ID 2023-11-28 03:54:47 +02:00
Bogdan
6d134750ff New: (Redacted) Add Freeload Only option 2023-11-27 12:06:18 +02:00
Bogdan
bbf9945b49 Add missing CSS typing 2023-11-27 05:34:03 +02:00
Bogdan
b66a85269f Add color to links in info inputs 2023-11-27 03:02:03 +02:00
Bogdan
81e9c29d54 Bump version to 1.11.0 2023-11-26 22:46:36 +02:00
55 changed files with 718 additions and 298 deletions

View File

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

View File

@@ -0,0 +1,13 @@
.message {
composes: alert from '~Components/Alert.css';
a {
color: var(--linkColor);
text-decoration: none;
&:hover {
color: var(--linkHoverColor);
text-decoration: underline;
}
}
}

View File

@@ -0,0 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'message': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import { kinds } from 'Helpers/Props';
import styles from './InfoInput.css';
class InfoInput extends Component {
@@ -12,7 +13,10 @@ class InfoInput extends Component {
const { value } = this.props;
return (
<Alert kind={kinds.INFO}>
<Alert
kind={kinds.INFO}
className={styles.message}
>
<span dangerouslySetInnerHTML={{ __html: value }} />
</Alert>
);

View File

@@ -15,5 +15,5 @@
"start_url": "../../../../",
"theme_color": "#3a3f51",
"background_color": "#3a3f51",
"display": "standalone"
"display": "minimal-ui"
}

View File

@@ -0,0 +1,13 @@
.links {
margin: 0;
}
.link {
white-space: nowrap;
}
.linkLabel {
composes: label from '~Components/Label.css';
cursor: pointer;
}

View File

@@ -0,0 +1,9 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'link': string;
'linkLabel': string;
'links': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -0,0 +1,90 @@
import React from 'react';
import Label from 'Components/Label';
import Link from 'Components/Link/Link';
import { kinds, sizes } from 'Helpers/Props';
import { IndexerCategory } from 'Indexer/Indexer';
import styles from './ReleaseLinks.css';
interface ReleaseLinksProps {
categories: IndexerCategory[];
imdbId?: string;
tmdbId?: number;
tvdbId?: number;
tvMazeId?: number;
}
function ReleaseLinks(props: ReleaseLinksProps) {
const { categories = [], imdbId, tmdbId, tvdbId, tvMazeId } = props;
const categoryNames = categories
.filter((item) => item.id < 100000)
.map((c) => c.name);
return (
<div className={styles.links}>
{imdbId ? (
<Link
className={styles.link}
to={`https://imdb.com/title/tt${imdbId.toString().padStart(7, '0')}/`}
>
<Label
className={styles.linkLabel}
kind={kinds.INFO}
size={sizes.LARGE}
>
IMDb
</Label>
</Link>
) : null}
{tmdbId ? (
<Link
className={styles.link}
to={`https://www.themoviedb.org/${
categoryNames.includes('Movies') ? 'movie' : 'tv'
}/${tmdbId}`}
>
<Label
className={styles.linkLabel}
kind={kinds.INFO}
size={sizes.LARGE}
>
TMDb
</Label>
</Link>
) : null}
{tvdbId ? (
<Link
className={styles.link}
to={`https://www.thetvdb.com/?tab=series&id=${tvdbId}`}
>
<Label
className={styles.linkLabel}
kind={kinds.INFO}
size={sizes.LARGE}
>
TVDb
</Label>
</Link>
) : null}
{tvMazeId ? (
<Link
className={styles.link}
to={`https://www.tvmaze.com/shows/${tvMazeId}/_`}
>
<Label
className={styles.linkLabel}
kind={kinds.INFO}
size={sizes.LARGE}
>
TV Maze
</Label>
</Link>
) : null}
</div>
);
}
export default ReleaseLinks;

View File

@@ -63,7 +63,7 @@
}
.externalLinks {
margin: 0 2px;
width: 22px;
text-align: center;
composes: button from '~Components/Link/IconButton.css';
color: var(--textColor);
}

View File

@@ -16,6 +16,7 @@ import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
import CategoryLabel from './CategoryLabel';
import Peers from './Peers';
import ReleaseLinks from './ReleaseLinks';
import styles from './SearchIndexRow.css';
function getDownloadIcon(isGrabbing, isGrabbed, grabError) {
@@ -118,6 +119,10 @@ class SearchIndexRow extends Component {
grabs,
seeders,
leechers,
imdbId,
tmdbId,
tvdbId,
tvMazeId,
indexerFlags,
columns,
isGrabbing,
@@ -343,6 +348,32 @@ class SearchIndexRow extends Component {
/> :
null
}
{
imdbId || tmdbId || tvdbId || tvMazeId ? (
<Popover
anchor={
<Icon
className={styles.externalLinks}
name={icons.EXTERNAL_LINK}
size={12}
/>
}
title={translate('Links')}
body={
<ReleaseLinks
categories={categories}
imdbId={imdbId}
tmdbId={tmdbId}
tvdbId={tvdbId}
tvMazeId={tvMazeId}
/>
}
kind={kinds.INVERSE}
position={tooltipPositions.TOP}
/>
) : null
}
</VirtualTableRowCell>
);
}
@@ -375,6 +406,10 @@ SearchIndexRow.propTypes = {
grabs: PropTypes.number,
seeders: PropTypes.number,
leechers: PropTypes.number,
imdbId: PropTypes.number,
tmdbId: PropTypes.number,
tvdbId: PropTypes.number,
tvMazeId: PropTypes.number,
indexerFlags: PropTypes.arrayOf(PropTypes.string).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onGrabPress: PropTypes.func.isRequired,

View File

@@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.IndexerTests.OrpheusTests
var torrentInfo = releases.First() as TorrentInfo;
torrentInfo.Title.Should().Be("The Beatles - Abbey Road [1969] [Album] [2.0 Mix 2019] [MP3 V2 (VBR)] [BD]");
torrentInfo.Title.Should().Be("The Beatles - Abbey Road (1969) [Album] [2.0 Mix 2019] [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");

View File

@@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.IndexerTests.RedactedTests
var torrentInfo = releases.First() as TorrentInfo;
torrentInfo.Title.Should().Be("Red Hot Chili Peppers - Californication [1999] [Album] [US / Reissue 2020] [FLAC 24bit Lossless] [Vinyl]");
torrentInfo.Title.Should().Be("Red Hot Chili Peppers - Californication (1999) [Album] [US / Reissue 2020] [FLAC 24bit Lossless / Vinyl]");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("https://redacted.ch/ajax.php?action=download&id=3892313");
torrentInfo.InfoUrl.Should().Be("https://redacted.ch/torrents.php?id=16720&torrentid=3892313");

View File

@@ -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="13.7.1" />
<PackageReference Include="YamlDotNet" Version="13.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Prowlarr.Test.Common.csproj" />

View File

@@ -9,8 +9,8 @@ namespace NzbDrone.Core.Datastore
{
public interface IConnectionStringFactory
{
string MainDbConnectionString { get; }
string LogDbConnectionString { get; }
DatabaseConnectionInfo MainDbConnection { get; }
DatabaseConnectionInfo LogDbConnection { get; }
string GetDatabasePath(string connectionString);
}
@@ -22,15 +22,15 @@ namespace NzbDrone.Core.Datastore
{
_configFileProvider = configFileProvider;
MainDbConnectionString = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) :
MainDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresMainDb) :
GetConnectionString(appFolderInfo.GetDatabase());
LogDbConnectionString = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) :
LogDbConnection = _configFileProvider.PostgresHost.IsNotNullOrWhiteSpace() ? GetPostgresConnectionString(_configFileProvider.PostgresLogDb) :
GetConnectionString(appFolderInfo.GetLogDatabase());
}
public string MainDbConnectionString { get; private set; }
public string LogDbConnectionString { get; private set; }
public DatabaseConnectionInfo MainDbConnection { get; private set; }
public DatabaseConnectionInfo LogDbConnection { get; private set; }
public string GetDatabasePath(string connectionString)
{
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Datastore
return connectionBuilder.DataSource;
}
private static string GetConnectionString(string dbPath)
private static DatabaseConnectionInfo GetConnectionString(string dbPath)
{
var connectionBuilder = new SQLiteConnectionStringBuilder
{
@@ -57,21 +57,22 @@ namespace NzbDrone.Core.Datastore
connectionBuilder.Add("Full FSync", true);
}
return connectionBuilder.ConnectionString;
return new DatabaseConnectionInfo(DatabaseType.SQLite, connectionBuilder.ConnectionString);
}
private string GetPostgresConnectionString(string dbName)
private DatabaseConnectionInfo GetPostgresConnectionString(string dbName)
{
var connectionBuilder = new NpgsqlConnectionStringBuilder();
var connectionBuilder = new NpgsqlConnectionStringBuilder
{
Database = dbName,
Host = _configFileProvider.PostgresHost,
Username = _configFileProvider.PostgresUser,
Password = _configFileProvider.PostgresPassword,
Port = _configFileProvider.PostgresPort,
Enlist = false
};
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;
return new DatabaseConnectionInfo(DatabaseType.PostgreSQL, connectionBuilder.ConnectionString);
}
}
}

View File

@@ -0,0 +1,14 @@
namespace NzbDrone.Core.Datastore
{
public class DatabaseConnectionInfo
{
public DatabaseConnectionInfo(DatabaseType databaseType, string connectionString)
{
DatabaseType = databaseType;
ConnectionString = connectionString;
}
public DatabaseType DatabaseType { get; internal set; }
public string ConnectionString { get; internal set; }
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Data.Common;
using System.Data.SQLite;
using System.Net.Sockets;
using System.Threading;
using NLog;
using Npgsql;
using NzbDrone.Common.Disk;
@@ -60,22 +61,22 @@ namespace NzbDrone.Core.Datastore
public IDatabase Create(MigrationContext migrationContext)
{
string connectionString;
DatabaseConnectionInfo connectionInfo;
switch (migrationContext.MigrationType)
{
case MigrationType.Main:
{
connectionString = _connectionStringFactory.MainDbConnectionString;
CreateMain(connectionString, migrationContext);
connectionInfo = _connectionStringFactory.MainDbConnection;
CreateMain(connectionInfo.ConnectionString, migrationContext, connectionInfo.DatabaseType);
break;
}
case MigrationType.Log:
{
connectionString = _connectionStringFactory.LogDbConnectionString;
CreateLog(connectionString, migrationContext);
connectionInfo = _connectionStringFactory.LogDbConnection;
CreateLog(connectionInfo.ConnectionString, migrationContext, connectionInfo.DatabaseType);
break;
}
@@ -90,14 +91,14 @@ namespace NzbDrone.Core.Datastore
{
DbConnection conn;
if (connectionString.Contains(".db"))
if (connectionInfo.DatabaseType == DatabaseType.SQLite)
{
conn = SQLiteFactory.Instance.CreateConnection();
conn.ConnectionString = connectionString;
conn.ConnectionString = connectionInfo.ConnectionString;
}
else
{
conn = new NpgsqlConnection(connectionString);
conn = new NpgsqlConnection(connectionInfo.ConnectionString);
}
conn.Open();
@@ -107,12 +108,12 @@ namespace NzbDrone.Core.Datastore
return db;
}
private void CreateMain(string connectionString, MigrationContext migrationContext)
private void CreateMain(string connectionString, MigrationContext migrationContext, DatabaseType databaseType)
{
try
{
_restoreDatabaseService.Restore();
_migrationController.Migrate(connectionString, migrationContext);
_migrationController.Migrate(connectionString, migrationContext, databaseType);
}
catch (SQLiteException e)
{
@@ -135,15 +136,17 @@ namespace NzbDrone.Core.Datastore
{
Logger.Error(e, "Failure to connect to Postgres DB, {0} retries remaining", retryCount);
Thread.Sleep(5000);
try
{
_migrationController.Migrate(connectionString, migrationContext);
_migrationController.Migrate(connectionString, migrationContext, databaseType);
return;
}
catch (Exception ex)
{
if (--retryCount > 0)
{
System.Threading.Thread.Sleep(5000);
continue;
}
@@ -162,11 +165,11 @@ namespace NzbDrone.Core.Datastore
}
}
private void CreateLog(string connectionString, MigrationContext migrationContext)
private void CreateLog(string connectionString, MigrationContext migrationContext, DatabaseType databaseType)
{
try
{
_migrationController.Migrate(connectionString, migrationContext);
_migrationController.Migrate(connectionString, migrationContext, databaseType);
}
catch (SQLiteException e)
{
@@ -186,7 +189,7 @@ namespace NzbDrone.Core.Datastore
Logger.Error("Unable to recreate logging database automatically. It will need to be removed manually.");
}
_migrationController.Migrate(connectionString, migrationContext);
_migrationController.Migrate(connectionString, migrationContext, databaseType);
}
catch (Exception e)
{

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
{
public interface IMigrationController
{
void Migrate(string connectionString, MigrationContext migrationContext);
void Migrate(string connectionString, MigrationContext migrationContext, DatabaseType databaseType);
}
public class MigrationController : IMigrationController
@@ -29,7 +29,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
_migrationLoggerProvider = migrationLoggerProvider;
}
public void Migrate(string connectionString, MigrationContext migrationContext)
public void Migrate(string connectionString, MigrationContext migrationContext, DatabaseType databaseType)
{
var sw = Stopwatch.StartNew();
@@ -37,7 +37,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
ServiceProvider serviceProvider;
var db = connectionString.Contains(".db") ? "sqlite" : "postgres";
var db = databaseType == DatabaseType.SQLite ? "sqlite" : "postgres";
serviceProvider = new ServiceCollection()
.AddLogging(b => b.AddNLog())

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using AngleSharp.Html.Parser;
using NLog;
@@ -10,6 +11,7 @@ using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions;
[Obsolete("Site has shutdown")]
public class AroLol : GazelleBase<AroLolSettings>
{
public override string Name => "aro.lol";

View File

@@ -7,6 +7,7 @@ using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Indexers.Definitions.Avistaz
@@ -15,9 +16,9 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
{
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override bool SupportsPagination => true;
public override bool SupportsPagination => false;
public override int PageSize => 50;
public override TimeSpan RateLimit => TimeSpan.FromSeconds(5);
public override TimeSpan RateLimit => TimeSpan.FromSeconds(6);
public override IndexerCapabilities Capabilities => SetCapabilities();
protected virtual string LoginUrl => Settings.BaseUrl + "api/v1/jackett/auth";
private IIndexerRepository _indexerRepository;
@@ -50,21 +51,28 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
return new AvistazParserBase();
}
protected virtual IndexerCapabilities SetCapabilities()
{
return new IndexerCapabilities();
}
protected abstract IndexerCapabilities SetCapabilities();
protected override async Task DoLogin()
{
Settings.Token = await GetToken();
if (Definition.Id > 0)
try
{
_indexerRepository.UpdateSettings((IndexerDefinition)Definition);
}
Settings.Token = await GetToken();
_logger.Debug("Avistaz authentication succeeded.");
if (Definition.Id > 0)
{
_indexerRepository.UpdateSettings((IndexerDefinition)Definition);
}
_logger.Debug("Avistaz authentication succeeded.");
}
catch (HttpException ex) when (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Warn(ex, "Failed to authenticate with Avistaz");
var jsonResponse = STJson.Deserialize<AvistazErrorResponse>(ex.Response.Content);
throw new IndexerAuthException(jsonResponse?.Message ?? "Unauthorized request to indexer");
}
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
@@ -116,11 +124,12 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
Method = HttpMethod.Post
};
// TODO: Change to HttpAccept.Json after they fix the issue with missing headers
var authLoginRequest = requestBuilder
.AddFormParameter("username", Settings.Username)
.AddFormParameter("password", Settings.Password)
.AddFormParameter("pid", Settings.Pid.Trim())
.Accept(HttpAccept.Json)
.Accept(HttpAccept.Html)
.Build();
var response = await ExecuteAuth(authLoginRequest);

View File

@@ -69,11 +69,22 @@ namespace NzbDrone.Core.Indexers.Definitions.Avistaz
DownloadVolumeFactor = row.DownloadMultiply,
UploadVolumeFactor = row.UploadMultiply,
MinimumRatio = 1,
MinimumSeedTime = 172800, // 48 hours
MinimumSeedTime = 259200, // 72 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.FileSize is > 0)
{
var sizeGigabytes = row.FileSize.Value / Math.Pow(1024, 3);
release.MinimumSeedTime = sizeGigabytes switch
{
> 50.0 => (long)((100 * Math.Log(sizeGigabytes)) - 219.2023) * 3600,
_ => 259200 + (long)(sizeGigabytes * 7200)
};
}
if (row.MovieTvinfo != null)
{
release.ImdbId = ParseUtil.GetImdbId(row.MovieTvinfo.Imdb).GetValueOrDefault();

View File

@@ -48,6 +48,13 @@ namespace NzbDrone.Core.Indexers.Definitions
return new BeyondHDParser(Capabilities.Categories);
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities

View File

@@ -9,7 +9,9 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
public class BroadcastheNet : TorrentIndexerBase<BroadcastheNetSettings>
{
public override string Name => "BroadcasTheNet";
public override string[] IndexerUrls => new[] { "https://api.broadcasthe.net/" };
public override string[] LegacyUrls => new[] { "http://api.broadcasthe.net/" };
public override string Description => "BroadcasTheNet (BTN) is an invite-only torrent tracker focused on TV shows";
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
@@ -18,11 +20,6 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
public override IndexerCapabilities Capabilities => SetCapabilities();
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)
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
{
@@ -30,18 +27,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
public override IIndexerRequestGenerator GetRequestGenerator()
{
var requestGenerator = new BroadcastheNetRequestGenerator() { Settings = Settings, PageSize = PageSize, Capabilities = Capabilities };
var releaseInfo = _indexerStatusService.GetLastRssSyncReleaseInfo(Definition.Id);
if (releaseInfo != null)
{
if (int.TryParse(releaseInfo.Guid.Replace("BTN-", string.Empty), out var torrentId))
{
requestGenerator.LastRecentTorrentID = torrentId;
}
}
return requestGenerator;
return new BroadcastheNetRequestGenerator { Settings = Settings, Capabilities = Capabilities, PageSize = PageSize };
}
public override IParseIndexerResponse GetParser()
@@ -65,7 +51,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
caps.Categories.AddCategoryMapping("720p", NewznabStandardCategory.TVHD, "720p");
caps.Categories.AddCategoryMapping("1080p", NewznabStandardCategory.TVHD, "1080p");
caps.Categories.AddCategoryMapping("1080i", NewznabStandardCategory.TVHD, "1080i");
caps.Categories.AddCategoryMapping("2160p", NewznabStandardCategory.TVHD, "2160p");
caps.Categories.AddCategoryMapping("2160p", NewznabStandardCategory.TVUHD, "2160p");
caps.Categories.AddCategoryMapping("Portable Device", NewznabStandardCategory.TVSD, "Portable Device");
return caps;

View File

@@ -25,7 +25,7 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var results = new List<ReleaseInfo>();
var releaseInfos = new List<ReleaseInfo>();
var indexerHttpResponse = indexerResponse.HttpResponse;
switch (indexerHttpResponse.StatusCode)
@@ -69,67 +69,76 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
if (jsonResponse.Result.Results == 0 || jsonResponse.Result?.Torrents?.Values == null)
{
return results;
return releaseInfos;
}
var protocol = indexerResponse.HttpRequest.Url.Scheme + ":";
foreach (var torrent in jsonResponse.Result.Torrents.Values)
{
var torrentInfo = new TorrentInfo();
var flags = new HashSet<IndexerFlag>();
torrentInfo.Guid = string.Format("BTN-{0}", torrent.TorrentID);
torrentInfo.Title = CleanReleaseName(torrent.ReleaseName);
torrentInfo.Size = torrent.Size;
torrentInfo.DownloadUrl = RegexProtocol.Replace(torrent.DownloadURL, protocol);
torrentInfo.InfoUrl = string.Format("{0}//broadcasthe.net/torrents.php?id={1}&torrentid={2}", protocol, torrent.GroupID, torrent.TorrentID);
//torrentInfo.CommentUrl =
if (torrent.TvdbID.HasValue)
if (torrent.Origin.ToUpperInvariant() == "INTERNAL")
{
torrentInfo.TvdbId = torrent.TvdbID.Value;
flags.Add(IndexerFlag.Internal);
}
if (torrent.TvrageID.HasValue)
var releaseInfo = new TorrentInfo
{
torrentInfo.TvRageId = torrent.TvrageID.Value;
Guid = $"BTN-{torrent.TorrentID}",
InfoUrl = $"{protocol}//broadcasthe.net/torrents.php?id={torrent.GroupID}&torrentid={torrent.TorrentID}",
DownloadUrl = RegexProtocol.Replace(torrent.DownloadURL, protocol),
Title = CleanReleaseName(torrent.ReleaseName),
Categories = _categories.MapTrackerCatToNewznab(torrent.Resolution),
InfoHash = torrent.InfoHash,
Size = torrent.Size,
Grabs = torrent.Snatched,
Seeders = torrent.Seeders,
Peers = torrent.Leechers + torrent.Seeders,
PublishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().AddSeconds(torrent.Time),
Origin = torrent.Origin,
Source = torrent.Source,
Container = torrent.Container,
Codec = torrent.Codec,
Resolution = torrent.Resolution,
Scene = torrent.Origin.ToUpperInvariant() == "SCENE",
IndexerFlags = flags,
DownloadVolumeFactor = 0,
UploadVolumeFactor = 1,
MinimumRatio = 1,
MinimumSeedTime = torrent.Category.ToUpperInvariant() == "SEASON" ? 432000 : 86400, // 120 hours for seasons and 24 hours for episodes
};
if (torrent.TvdbID is > 0)
{
releaseInfo.TvdbId = torrent.TvdbID.Value;
}
torrentInfo.PublishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().AddSeconds(torrent.Time);
if (torrent.TvrageID is > 0)
{
releaseInfo.TvRageId = torrent.TvrageID.Value;
}
//torrentInfo.MagnetUrl =
torrentInfo.InfoHash = torrent.InfoHash;
torrentInfo.Seeders = torrent.Seeders;
torrentInfo.Peers = torrent.Leechers + torrent.Seeders;
torrentInfo.Origin = torrent.Origin;
torrentInfo.Source = torrent.Source;
torrentInfo.Container = torrent.Container;
torrentInfo.Codec = torrent.Codec;
torrentInfo.Resolution = torrent.Resolution;
torrentInfo.UploadVolumeFactor = 1;
torrentInfo.DownloadVolumeFactor = 0;
torrentInfo.MinimumRatio = 1;
torrentInfo.Categories = _categories.MapTrackerCatToNewznab(torrent.Resolution);
if (torrent.ImdbID.IsNotNullOrWhiteSpace() && int.TryParse(torrent.ImdbID, out var imdbId))
{
releaseInfo.ImdbId = imdbId;
}
// Default to TV if category could not be mapped
if (torrentInfo.Categories == null || !torrentInfo.Categories.Any())
if (releaseInfo.Categories == null || !releaseInfo.Categories.Any())
{
torrentInfo.Categories = new List<IndexerCategory> { NewznabStandardCategory.TV };
releaseInfo.Categories = new List<IndexerCategory> { NewznabStandardCategory.TV };
}
results.Add(torrentInfo);
releaseInfos.Add(releaseInfo);
}
return results;
return releaseInfos;
}
private string CleanReleaseName(string releaseName)
{
releaseName = releaseName.Replace("\\", "");
return releaseName;
return releaseName.Replace("\\", "");
}
}
}

View File

@@ -9,31 +9,13 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
{
public class BroadcastheNetRequestGenerator : IIndexerRequestGenerator
{
public int MaxPages { get; set; }
public int PageSize { get; set; }
public BroadcastheNetSettings Settings { get; set; }
public IndexerCapabilities Capabilities { get; set; }
public int? LastRecentTorrentID { get; set; }
public int PageSize { get; set; }
public Func<IDictionary<string, string>> GetCookies { get; set; }
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public BroadcastheNetRequestGenerator()
{
MaxPages = 10;
PageSize = 100;
}
private IEnumerable<IndexerRequest> GetPagedRequests(BroadcastheNetTorrentQuery parameters, int results, int offset)
{
var builder = new JsonRpcRequestBuilder(Settings.BaseUrl)
.Call("getTorrents", Settings.ApiKey, parameters, results, offset);
builder.SuppressHttpError = true;
yield return new IndexerRequest(builder.Build());
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
@@ -132,11 +114,24 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
var btnOffset = searchCriteria.Offset.GetValueOrDefault(0);
parameters.Search = searchString.Replace(" ", "%");
if (searchString.IsNotNullOrWhiteSpace())
{
parameters.Search = searchString.Replace(" ", "%");
}
pageableRequests.Add(GetPagedRequests(parameters, btnResults, btnOffset));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetPagedRequests(BroadcastheNetTorrentQuery parameters, int results, int offset)
{
var builder = new JsonRpcRequestBuilder(Settings.BaseUrl)
.Call("getTorrents", Settings.ApiKey, parameters, results, offset);
builder.SuppressHttpError = true;
yield return new IndexerRequest(builder.Build());
}
}
}

View File

@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace NzbDrone.Core.Indexers.BroadcastheNet
{
@@ -13,15 +14,15 @@ namespace NzbDrone.Core.Indexers.BroadcastheNet
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Search { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Codec { get; set; }
public IEnumerable<string> Codec { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Container { get; set; }
public IEnumerable<string> Container { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Source { get; set; }
public IEnumerable<string> Source { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Resolution { get; set; }
public IEnumerable<string> Resolution { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Origin { get; set; }
public IEnumerable<string> Origin { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Hash { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]

View File

@@ -1,7 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.FileList;
@@ -40,6 +43,13 @@ public class FileList : TorrentIndexerBase<FileListSettings>
return new FileListParser(Settings, Capabilities.Categories);
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities

View File

@@ -73,6 +73,13 @@ namespace NzbDrone.Core.Indexers.Definitions
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
private IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities
@@ -293,6 +300,10 @@ namespace NzbDrone.Core.Indexers.Definitions
var parser = new HtmlParser();
using var doc = parser.ParseDocument(indexerResponse.Content);
var headerColumns = doc.QuerySelectorAll("table[id=\"torrents\"] > thead > tr > th").Select(x => x.TextContent.Trim()).ToList();
var sizeIndex = FindColumnIndexOrDefault(headerColumns, "Sort by size", 5);
var filesIndex = FindColumnIndexOrDefault(headerColumns, "Sort by files");
var rows = doc.QuerySelectorAll("table[id=\"torrents\"] > tbody > tr");
foreach (var row in rows)
{
@@ -314,7 +325,6 @@ namespace NzbDrone.Core.Indexers.Definitions
var dateSplit = descrSplit.Last().Split(new[] { " by " }, StringSplitOptions.None);
var publishDate = DateTimeUtil.FromTimeAgo(dateSplit.First());
var description = descrSplit.Length > 1 ? "Tags: " + descrSplit.First().Trim() : "";
description += dateSplit.Length > 1 ? " Uploaded by: " + dateSplit.Last().Trim() : "";
var catIcon = row.QuerySelector("td:nth-of-type(1) a");
if (catIcon == null)
@@ -327,36 +337,40 @@ namespace NzbDrone.Core.Indexers.Definitions
// Torrents - Category column == Icons
var cat = _categories.MapTrackerCatToNewznab(catIcon.GetAttribute("href").Substring(1));
var size = ParseUtil.GetBytes(row.Children[5].TextContent);
var size = ParseUtil.GetBytes(row.Children[sizeIndex].TextContent);
var colIndex = 6;
int? files = null;
if (row.Children.Length == 10)
if (filesIndex != -1)
{
files = ParseUtil.CoerceInt(row.Children[colIndex].TextContent.Replace("Go to files", ""));
colIndex++;
files = ParseUtil.CoerceInt(row.Children[filesIndex].TextContent.Replace("Go to files", ""));
}
var grabs = ParseUtil.CoerceInt(row.Children[colIndex++].TextContent);
var seeders = ParseUtil.CoerceInt(row.Children[colIndex++].TextContent);
var leechers = ParseUtil.CoerceInt(row.Children[colIndex].TextContent);
var dlVolumeFactor = row.QuerySelector("span.free") != null ? 0 : 1;
var colIndex = row.Children.Length == 10 ? 7 : 6;
var grabsIndex = FindColumnIndexOrDefault(headerColumns, "Sort by snatches", colIndex++);
var seedersIndex = FindColumnIndexOrDefault(headerColumns, "Sort by seeders", colIndex++);
var leechersIndex = FindColumnIndexOrDefault(headerColumns, "Sort by leechers", colIndex);
var grabs = ParseUtil.CoerceInt(row.Children[grabsIndex].TextContent);
var seeders = ParseUtil.CoerceInt(row.Children[seedersIndex].TextContent);
var leechers = ParseUtil.CoerceInt(row.Children[leechersIndex].TextContent);
var release = new TorrentInfo
{
Title = title,
Guid = details.AbsoluteUri,
DownloadUrl = link.AbsoluteUri,
InfoUrl = details.AbsoluteUri,
PublishDate = publishDate,
Title = title,
Description = description,
Categories = cat,
Size = size,
Files = files,
Grabs = grabs,
Seeders = seeders,
Peers = seeders + leechers,
DownloadVolumeFactor = dlVolumeFactor,
PublishDate = publishDate,
DownloadVolumeFactor = row.QuerySelector("span.free") != null ? 0 : 1,
UploadVolumeFactor = 1,
MinimumRatio = 1,
MinimumSeedTime = 1209600 // 336 hours
@@ -368,6 +382,13 @@ namespace NzbDrone.Core.Indexers.Definitions
return torrentInfos.ToArray();
}
private static int FindColumnIndexOrDefault(List<string> columns, string name, int defaultIndex = -1)
{
var index = columns.FindIndex(x => x.Equals(name, StringComparison.Ordinal));
return index != -1 ? index : defaultIndex;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
private static string CleanTitle(string title)

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using AngleSharp.Dom;
@@ -76,12 +75,16 @@ public class NorBits : TorrentIndexerBase<NorBitsSettings>
{
LogResponseContent = true,
AllowAutoRedirect = true,
Method = HttpMethod.Post
SuppressHttpError = true
};
var authLoginCheckRequest = requestBuilder3
.Post()
.AddFormParameter("username", Settings.Username)
.AddFormParameter("password", Settings.Password)
.AddFormParameter("code", Settings.TwoFactorAuthCode ?? string.Empty)
.AddFormParameter("logout", "no")
.AddFormParameter("returnto", "/")
.SetCookies(indexPage.GetCookies())
.SetHeader("Referer", loginUrl)
.Build();
@@ -174,6 +177,11 @@ public class NorBitsRequestGenerator : IIndexerRequestGenerator
{ "scenerelease", "0" }
};
if (_settings.FreeLeechOnly)
{
parameters.Set("FL", "1");
}
var searchTerm = "search=";
if (!string.IsNullOrWhiteSpace(imdbId))
@@ -343,6 +351,12 @@ public class NorBitsSettings : UserPassTorrentBaseSettings
UseFullSearch = false;
}
[FieldDefinition(4, Label = "Use Full Search", HelpText = "Use Full Search from Site", Type = FieldType.Checkbox)]
[FieldDefinition(4, Label = "2FA code", Type = FieldType.Textbox, HelpText = "Only fill in the <b>2FA code</b> box if you have enabled <b>2FA</b> on the NorBits Web Site. Otherwise just leave it empty.")]
public string TwoFactorAuthCode { get; set; }
[FieldDefinition(5, Label = "Use Full Search", Type = FieldType.Checkbox, HelpText = "Use Full Search from Site")]
public bool UseFullSearch { get; set; }
[FieldDefinition(6, Label = "FreeLeech Only", Type = FieldType.Checkbox, HelpText = "Search FreeLeech torrents only")]
public bool FreeLeechOnly { get; set; }
}

View File

@@ -362,7 +362,7 @@ namespace NzbDrone.Core.Indexers.Definitions
private string GetTitle(GazelleRelease result, GazelleTorrent torrent)
{
var title = $"{result.Artist} - {result.GroupName} [{result.GroupYear}]";
var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear})";
if (result.ReleaseType.IsNotNullOrWhiteSpace() && result.ReleaseType != "Unknown")
{
@@ -374,14 +374,23 @@ namespace NzbDrone.Core.Indexers.Definitions
title += $" [{$"{torrent.RemasterTitle} {torrent.RemasterYear}".Trim()}]";
}
title += $" [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
var flags = new List<string>
{
$"{torrent.Format} {torrent.Encoding}",
$"{torrent.Media}"
};
if (torrent.HasLog)
{
flags.Add("Log (" + torrent.LogScore + "%)");
}
if (torrent.HasCue)
{
title += " [Cue]";
flags.Add("Cue");
}
return title;
return $"{title} [{string.Join(" / ", flags)}]";
}
private string GetDownloadUrl(int torrentId, bool canUseToken)
@@ -392,7 +401,7 @@ namespace NzbDrone.Core.Indexers.Definitions
.AddQueryParam("id", torrentId);
// Orpheus fails to download if usetoken=0 so we need to only add if we will use one
if (_settings.UseFreeleechToken)
if (_settings.UseFreeleechToken && canUseToken)
{
url = url.AddQueryParam("usetoken", "1");
}

View File

@@ -94,7 +94,12 @@ namespace NzbDrone.Core.Indexers.Definitions.PassThePopcorn
ImdbId = result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0,
Scene = torrent.Scene,
IndexerFlags = flags,
DownloadVolumeFactor = torrent.FreeleechType is "Freeleech" ? 0 : 1,
DownloadVolumeFactor = torrent.FreeleechType?.ToUpperInvariant() switch
{
"FREELEECH" => 0,
"HALF LEECH" => 0.5,
_ => 1
},
UploadVolumeFactor = 1,
MinimumRatio = 1,
MinimumSeedTime = 345600,

View File

@@ -193,6 +193,11 @@ namespace NzbDrone.Core.Indexers.Definitions
queryCats.ForEach(cat => parameters.Set($"filter_cat[{cat}]", "1"));
}
if (_settings.FreeloadOnly)
{
parameters.Set("freetorrent", "4");
}
var searchUrl = _settings.BaseUrl.TrimEnd('/') + $"/ajax.php?{parameters.GetQueryString()}";
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
@@ -242,6 +247,12 @@ namespace NzbDrone.Core.Indexers.Definitions
{
foreach (var torrent in result.Torrents)
{
// skip non-freeload results when freeload only is set
if (_settings.FreeloadOnly && !torrent.IsFreeload)
{
continue;
}
var id = torrent.TorrentId;
var title = GetTitle(result, torrent);
@@ -251,7 +262,7 @@ namespace NzbDrone.Core.Indexers.Definitions
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken),
DownloadUrl = GetDownloadUrl(id, torrent.CanUseToken && !torrent.IsFreeload),
Title = WebUtility.HtmlDecode(title),
Artist = WebUtility.HtmlDecode(result.Artist),
Album = WebUtility.HtmlDecode(result.GroupName),
@@ -286,6 +297,12 @@ namespace NzbDrone.Core.Indexers.Definitions
// Non-Audio files are formatted a little differently (1:1 for group and torrents)
else
{
// skip non-freeload results when freeload only is set
if (_settings.FreeloadOnly && !result.IsFreeload)
{
continue;
}
var id = result.TorrentId;
var infoUrl = GetInfoUrl(result.GroupId, id);
@@ -294,7 +311,7 @@ namespace NzbDrone.Core.Indexers.Definitions
Guid = infoUrl,
Title = WebUtility.HtmlDecode(result.GroupName),
Size = long.Parse(result.Size),
DownloadUrl = GetDownloadUrl(id, result.CanUseToken),
DownloadUrl = GetDownloadUrl(id, result.CanUseToken && !result.IsFreeload),
InfoUrl = infoUrl,
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
@@ -328,7 +345,7 @@ namespace NzbDrone.Core.Indexers.Definitions
private string GetTitle(GazelleRelease result, GazelleTorrent torrent)
{
var title = $"{result.Artist} - {result.GroupName} [{result.GroupYear}]";
var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear})";
if (result.ReleaseType.IsNotNullOrWhiteSpace() && result.ReleaseType != "Unknown")
{
@@ -340,14 +357,23 @@ namespace NzbDrone.Core.Indexers.Definitions
title += $" [{$"{torrent.RemasterTitle} {torrent.RemasterYear}".Trim()}]";
}
title += $" [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
var flags = new List<string>
{
$"{torrent.Format} {torrent.Encoding}",
$"{torrent.Media}"
};
if (torrent.HasLog)
{
flags.Add("Log (" + torrent.LogScore + "%)");
}
if (torrent.HasCue)
{
title += " [Cue]";
flags.Add("Cue");
}
return title;
return $"{title} [{string.Join(" / ", flags)}]";
}
private string GetDownloadUrl(int torrentId, bool canUseToken)
@@ -394,12 +420,15 @@ namespace NzbDrone.Core.Indexers.Definitions
UseFreeleechToken = false;
}
[FieldDefinition(2, Label = "API Key", HelpText = "API Key from the Site (Found in Settings => Access Settings)", Privacy = PrivacyLevel.ApiKey)]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "API Key from the Site (Found in Settings => Access Settings)")]
public string Apikey { get; set; }
[FieldDefinition(3, Label = "Use Freeleech Tokens", HelpText = "Use freeleech tokens when available", Type = FieldType.Checkbox)]
[FieldDefinition(3, Label = "Use Freeleech Tokens", Type = FieldType.Checkbox, HelpText = "Use freeleech tokens when available")]
public bool UseFreeleechToken { get; set; }
[FieldDefinition(4, Label = "Freeload Only", Type = FieldType.Checkbox, Advanced = true, HelpTextWarning = "Search freeload torrents only. End date: 6 January 2024, 23:59 UTC.")]
public bool FreeloadOnly { get; set; }
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -1,10 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions
{
@@ -22,13 +19,6 @@ namespace NzbDrone.Core.Indexers.Definitions
{
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
protected override IndexerCapabilities SetCapabilities()
{
var caps = new IndexerCapabilities

View File

@@ -3,7 +3,6 @@ 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.Text.RegularExpressions;
@@ -51,6 +50,13 @@ namespace NzbDrone.Core.Indexers.Definitions
return new SpeedAppParser(Settings, Capabilities.Categories, MinimumSeedTime);
}
protected override IList<ReleaseInfo> CleanupReleases(IEnumerable<ReleaseInfo> releases, SearchCriteriaBase searchCriteria)
{
var cleanReleases = base.CleanupReleases(releases, searchCriteria);
return FilterReleasesByQuery(cleanReleases, searchCriteria).ToList();
}
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
{
return Settings.ApiKey.IsNullOrWhiteSpace() || httpResponse.StatusCode == HttpStatusCode.Unauthorized;
@@ -58,14 +64,13 @@ namespace NzbDrone.Core.Indexers.Definitions
protected override async Task DoLogin()
{
var requestBuilder = new HttpRequestBuilder(LoginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true,
Method = HttpMethod.Post,
};
var request = requestBuilder.Build();
var request = new HttpRequestBuilder(LoginUrl)
{
LogResponseContent = true,
AllowAutoRedirect = true
}
.Post()
.Build();
var data = new SpeedAppAuthenticationRequest
{

View File

@@ -110,7 +110,8 @@ namespace NzbDrone.Core.Indexers.Definitions
BookSearchParams = new List<BookSearchParam>
{
BookSearchParam.Q
}
},
SupportsRawSearch = true
};
caps.Categories.AddCategoryMapping("117", NewznabStandardCategory.Movies, "Українське кіно");

View File

@@ -138,6 +138,10 @@ namespace NzbDrone.Core.Indexers
{
torrentRelease.IndexerFlags.Add(IndexerFlag.FreeLeech);
}
else if (torrentRelease.DownloadVolumeFactor == 0.5)
{
torrentRelease.IndexerFlags.Add(IndexerFlag.HalfLeech);
}
if (torrentRelease.UploadVolumeFactor == 0.0)
{

View File

@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Indexers
}
catch
{
_logger.Trace("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData));
_logger.Info("Invalid torrent file contents: {0}", Encoding.ASCII.GetString(fileData));
throw;
}
}

View File

@@ -88,16 +88,15 @@ namespace NzbDrone.Core.Instrumentation
log.Level = logEvent.Level.Name;
var connectionString = _connectionStringFactory.LogDbConnectionString;
var connectionInfo = _connectionStringFactory.LogDbConnection;
//TODO: Probably need more robust way to differentiate what's being used
if (connectionString.Contains(".db"))
if (connectionInfo.DatabaseType == DatabaseType.SQLite)
{
WriteSqliteLog(log, connectionString);
WriteSqliteLog(log, connectionInfo.ConnectionString);
}
else
{
WritePostgresLog(log, connectionString);
WritePostgresLog(log, connectionInfo.ConnectionString);
}
}
catch (NpgsqlException ex)
@@ -136,8 +135,10 @@ namespace NzbDrone.Core.Instrumentation
private void WriteSqliteLog(Log log, string connectionString)
{
using (var connection =
new SQLiteConnection(connectionString).OpenAndReturn())
SQLiteFactory.Instance.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
using (var sqlCommand = connection.CreateCommand())
{
sqlCommand.CommandText = INSERT_COMMAND;

View File

@@ -1,7 +1,7 @@
{
"Add": "Přidat",
"CertificateValidation": "Ověření certifikátu",
"DeleteBackupMessageText": "Opravdu chcete smazat zálohu „{0}“?",
"DeleteBackupMessageText": "Opravdu chcete odstranit zálohu '{name}'?",
"YesCancel": "Ano, zrušit",
"About": "O aplikaci",
"Component": "Komponenta",
@@ -35,7 +35,7 @@
"Warn": "Varovat",
"Wiki": "Wiki",
"Connections": "Připojení",
"DeleteDownloadClientMessageText": "Opravdu chcete odstranit klienta pro stahování „{0}“?",
"DeleteDownloadClientMessageText": "Opravdu chcete odstranit klienta pro stahování '{name}'?",
"Details": "Detaily",
"Disabled": "Zakázáno",
"Docker": "Přístavní dělník",
@@ -114,7 +114,7 @@
"AcceptConfirmationModal": "Přijměte potvrzovací modální okno",
"Actions": "Akce",
"Added": "Přidáno",
"AddIndexer": "Přidat indexátor",
"AddIndexer": "Přidat indexer",
"LaunchBrowserHelpText": " Otevřete webový prohlížeč a při spuštění aplikace přejděte na domovskou stránku {appName}.",
"Logging": "Protokolování",
"Mechanism": "Mechanismus",
@@ -249,7 +249,7 @@
"DeleteApplicationMessageText": "Opravdu chcete smazat oznámení „{0}“?",
"DeleteBackup": "Odstranit zálohu",
"DeleteDownloadClient": "Odstranit staženého klienta",
"DeleteNotificationMessageText": "Opravdu chcete smazat oznámení „{0}“?",
"DeleteNotificationMessageText": "Opravdu chcete smazat oznámení '{name}'?",
"DeleteTagMessageText": "Opravdu chcete smazat značku „{0}“?",
"Discord": "Svár",
"DownloadClient": "Stáhnout klienta",
@@ -333,22 +333,22 @@
"More": "Více",
"ApplyTagsHelpTextAdd": "Přidat: Přidá značky k již existujícímu seznamu",
"ApplyTagsHelpTextHowToApplyApplications": "Jak použít značky na vybrané filmy",
"DeleteSelectedDownloadClients": "Odstranit staženého klienta",
"DeleteSelectedIndexersMessageText": "Opravdu chcete odstranit indexer „{0}“?",
"DeleteSelectedDownloadClients": "Odstranit klienta pro stahování",
"DeleteSelectedIndexersMessageText": "Opravdu chcete smazat {count} vybraný(ch) indexer(ů)?",
"DeleteSelectedApplicationsMessageText": "Opravdu chcete odstranit indexer „{0}“?",
"DeleteSelectedDownloadClientsMessageText": "Opravdu chcete odstranit indexer „{0}“?",
"DeleteSelectedDownloadClientsMessageText": "Opravdu chcete smazat {count} vybraných klientů pro stahování?",
"Year": "Rok",
"ApplyTagsHelpTextRemove": "Odebrat: Odebrat zadané značky",
"DownloadClientPriorityHelpText": "Upřednostněte více klientů pro stahování. Round-Robin se používá pro klienty se stejnou prioritou.",
"ApplyTagsHelpTextHowToApplyIndexers": "Jak použít značky na vybrané indexátory",
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit značky zadanými značkami (zadáním žádné značky vymažete všechny značky)",
"ApplyTagsHelpTextHowToApplyIndexers": "Jak použít značky na vybrané indexery",
"ApplyTagsHelpTextReplace": "Nahradit: Nahradit značky zadanými značkami (prázdné pole vymaže všechny značky)",
"Track": "Stopa",
"Genre": "Žánry",
"ConnectionLostReconnect": "{appName} se pokusí připojit automaticky, nebo můžete kliknout na tlačítko znovunačtení níže.",
"RecentChanges": "Nedávné změny",
"WhatsNew": "Co je nového?",
"DeleteAppProfileMessageText": "Opravdu chcete smazat kvalitní profil {0}",
"ConnectionLostToBackend": "{appName} ztratila spojení s backendem a pro obnovení funkčnosti bude třeba ji znovu načíst.",
"ConnectionLostToBackend": "{appName} ztratil spojení s backendem a pro obnovení funkčnosti bude třebaho znovu načíst.",
"minutes": "Minut",
"ApplicationURL": "URL aplikace",
"ApplicationUrlHelpText": "Externí adresa URL této aplikace včetně http(s)://, portu a základní adresy URL",
@@ -361,29 +361,29 @@
"AddCustomFilter": "Přidat vlastní filtr",
"AddConnection": "Přidat spojení",
"AddConnectionImplementation": "Přidat spojení - {implementationName}",
"AddIndexerImplementation": "Přidat indexátor - {implementationName}",
"AddIndexerImplementation": "Přidat indexer - {implementationName}",
"Publisher": "Vydavatel",
"Categories": "Kategorie",
"Notification": "Oznámení",
"AddApplicationImplementation": "Přidat spojení - {implementationName}",
"AddIndexerProxyImplementation": "Přidat indexátor - {implementationName}",
"Artist": "umělec",
"EditIndexerImplementation": "Přidat indexátor - {implementationName}",
"Artist": "Umělec",
"EditIndexerImplementation": "Upravit indexer - {implementationName}",
"Episode": "epizoda",
"NotificationStatusAllClientHealthCheckMessage": "Všechny seznamy nejsou k dispozici z důvodu selhání",
"NotificationStatusSingleClientHealthCheckMessage": "Seznamy nejsou k dispozici z důvodu selhání: {0}",
"Application": "Aplikace",
"AppUpdatedVersion": "{appName} byla aktualizována na verzi `{version}`, abyste získali nejnovější změny, musíte znovu načíst {appName}.",
"AppUpdatedVersion": "{appName} byl aktualizován na verzi `{version}`, abyste získali nejnovější změny, musíte znovu načíst {appName}",
"Encoding": "Kódování",
"Notifications": "Oznámení",
"Season": "Řada",
"Theme": "Motiv",
"Label": "Etiketa",
"Album": "album",
"Album": "Album",
"Applications": "Aplikace",
"Connect": "Oznámení",
"EditConnectionImplementation": "Přidat spojení - {implementationName}",
"EditDownloadClientImplementation": "Přidat klienta pro stahování - {implementationName}",
"EditDownloadClientImplementation": "Upravit klienta pro stahování - {implementationName}",
"AuthForm": "Formuláře (přihlašovací stránka)",
"Clone": "Klonovat",
"DefaultNameCopiedProfile": "{name} - Kopírovat",
@@ -393,9 +393,17 @@
"ResetAPIKeyMessageText": "Opravdu chcete resetovat klíč API?",
"Database": "Databáze",
"CountDownloadClientsSelected": "{count} vybraných klientů ke stahování",
"CountIndexersSelected": "{count} vybraných indexátorů",
"CountIndexersSelected": "{count} vybraných indexerů",
"EditIndexerProxyImplementation": "Přidat indexátor - {implementationName}",
"AuthBasic": "Základní (vyskakovací okno prohlížeče)",
"AuthenticationRequiredWarning": "Aby se zabránilo vzdálenému přístupu bez ověření, vyžaduje nyní {appName} povolení ověření. Ověřování z místních adres můžete volitelně zakázat.",
"RestartProwlarr": "Restartujte {appName}"
"RestartProwlarr": "Restartujte {appName}",
"Duration": "Trvání",
"EditSelectedDownloadClients": "Upravit vybrané klienty pro stahování",
"EditSelectedIndexers": "Upravit vybrané indexery",
"AuthenticationMethod": "Metoda ověřování",
"AuthenticationRequiredPasswordHelpTextWarning": "Vložte nové heslo",
"AuthenticationRequiredUsernameHelpTextWarning": "Vložte nové uživatelské jméno",
"AuthenticationMethodHelpTextWarning": "Prosím vyberte platnou metodu ověřování",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Potvrďte nové heslo"
}

View File

@@ -280,23 +280,23 @@
"ProwlarrSupportsAnyIndexer": "{appName} 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.",
"Proxies": "Proxies",
"Proxy": "Proxy",
"ProxyBypassFilterHelpText": "Verwende ',' als Trennzeichen und '*.' als Platzhalter für Subdomains",
"ProxyBypassFilterHelpText": "Verwenden Sie ',' als Trennzeichen und '*.' als Wildcard für Subdomains",
"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}",
"ProxyPasswordHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.",
"ProxyType": "Proxy Typ",
"ProxyUsernameHelpText": "Nur wenn ein Benutzername und Passwort erforderlich ist, muss es eingegeben werden. Ansonsten leer lassen.",
"ProxyPasswordHelpText": "Sie müssen nur einen Benutzernamen und ein Passwort eingeben, wenn dies erforderlich ist. Andernfalls lassen Sie sie leer.",
"ProxyType": "Proxy-Typ",
"ProxyUsernameHelpText": "Sie müssen nur einen Benutzernamen und ein Passwort eingeben, wenn dies erforderlich ist. Andernfalls lassen Sie sie leer.",
"Public": "Öffentlich",
"Query": "Abfrage",
"QueryOptions": "Abfrage-Optionen",
"QueryResults": "Abfrageergebnisse",
"Queue": "Warteschlange",
"Queued": "In der Warteschlange",
"Queued": "In Warteschlange",
"RSS": "RSS",
"RSSIsNotSupportedWithThisIndexer": "RSS wird von diesem Indexer nicht unterstützt",
"RawSearchSupported": "Raw-Suche unterstützt",
"ReadTheWikiForMoreInformation": "Lese das Wiki für mehr Informationen",
"ReadTheWikiForMoreInformation": "Lesen Sie das Wiki für weitere Informationen",
"Reddit": "Reddit",
"Redirect": "Umleiten",
"RedirectHelpText": "Eingehende Download-Anfragen für den Indexer umleiten, anstatt Proxying mit {appName}",
@@ -493,7 +493,7 @@
"Book": "Buch",
"ConnectionLostReconnect": "Radarr wird automatisch versuchen zu verbinden oder klicke unten auf neuladen.",
"ConnectionLostToBackend": "Radarr hat die Verbindung zum Backend verloren und muss neugeladen werden.",
"RecentChanges": "Neuste Änderungen",
"RecentChanges": "Kürzliche Änderungen",
"WhatsNew": "Was gibt's Neues?",
"minutes": "Minuten",
"DeleteAppProfileMessageText": "Qualitätsprofil '{0}' wirklich löschen?",
@@ -516,5 +516,21 @@
"VipExpiration": "VIP Ablaufdatum",
"TotalUserAgentQueries": "Gesamte Nutzeragent Anfragen",
"ActiveApps": "Aktive Apps",
"ActiveIndexers": "Aktive Indexer"
"ActiveIndexers": "Aktive Indexer",
"AppsMinimumSeeders": "Apps Mindestanzahl von Seedern",
"ApplicationTagsHelpText": "Synchronisiere Indexer für diese Anwendung die keine passenden Tags oder mindestens 1 passendes Tag haben",
"ApplicationTagsHelpTextWarning": "Tags sollten mit Vorsicht verwendet werden, da sie ungewollte Effekte haben können. Eine Anwendung mit einem Tag synchronisiert nur Indexer die den Gleichen Tag haben.",
"AddApplicationImplementation": "Anwendung hinzufügen - {implementationName}",
"AddConnectionImplementation": "Verbindung hinzufügen - {implementationName}",
"AddDownloadClientImplementation": "Download-Client hinzufügen - {implementationName}",
"AddIndexerImplementation": "Indexer hinzufügen - {implementationName}",
"AddIndexerProxyImplementation": "Indexer Proxy hinzufügen - {implementationName}",
"AppUpdatedVersion": "{appName} wurde auf die Version `{version}` aktualisiert. Um die neusten Funktionen zu bekommen lade {appName} neu",
"AuthenticationRequiredWarning": "Um unberechtigte Fernzugriffe zu vermeiden benötigt {appName} jetzt , dass Authentifizierung eingeschaltet ist. Du kannst Authentifizierung optional für lokale Adressen ausschalten.",
"AuthenticationRequired": "Authentifizierung benötigt",
"AuthenticationRequiredHelpText": "Ändern, welche anfragen Authentifizierung benötigen. Ändere nichts wenn du dir nicht des Risikos bewusst bist.",
"AuthenticationRequiredUsernameHelpTextWarning": "Gib einen neuen Benutzernamen ein",
"AuthenticationMethodHelpTextWarning": "Bitte wähle eine gültige Authentifizierungsmethode aus",
"AuthenticationRequiredPasswordHelpTextWarning": "Gib ein neues Passwort ein",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Neues Passwort bestätigen"
}

View File

@@ -1,7 +1,7 @@
{
"Indexers": "Indexadores",
"Host": "Host",
"History": "Historia",
"History": "Historial",
"HideAdvanced": "Ocultar Avanzado",
"Health": "Salud",
"General": "General",
@@ -53,7 +53,7 @@
"Queue": "Cola",
"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}",
"ProxyCheckBadRequestMessage": "Fallo al comprobar el proxy. Status code: {0}",
"Proxy": "Proxy",
"Options": "Opciones",
"NoChange": "Sin Cambio",
@@ -65,7 +65,7 @@
"IndexerStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores",
"Added": "Añadido",
"Actions": "Acciones",
"UISettingsSummary": "Calendario, fecha y opciones de color deteriorado",
"UISettingsSummary": "Fecha, idioma, y opciones de color deteriorado",
"TagsSettingsSummary": "Ver todas las etiquetas y cómo se usan. Las etiquetas no utilizadas se pueden eliminar",
"Size": "Tamaño",
"ReleaseStatus": "Estado del Estreno",
@@ -74,14 +74,14 @@
"IndexerStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}",
"Indexer": "Indexador",
"Grabbed": "Añadido",
"GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas y actualizaciones",
"GeneralSettingsSummary": "Puerto, SSL, nombre de usuario/contraseña , proxy, analíticas, y actualizaciones",
"Filename": "Nombre del archivo",
"Failed": "Fallido",
"EventType": "Tipo de Evento",
"DownloadClientsSettingsSummary": "Gestores de descargas, manipulación de descargas y mapeados remotos",
"DownloadClientsSettingsSummary": "Configuración del cliente de descargas para la integración en {appName} UI search",
"DownloadClient": "Gestor de Descargas",
"Details": "Detalles",
"ConnectSettingsSummary": "Notificaciones, conexiones a servidores/reproductores y scripts personalizados",
"ConnectSettingsSummary": "Notificaciones y scripts personalizados",
"Warn": "Advertencia",
"Type": "Tipo",
"Title": "Título",
@@ -140,10 +140,10 @@
"DeleteBackup": "Borrar Backup",
"DBMigration": "Migración de DB",
"CloneProfile": "Clonar Perfil",
"ClientPriority": "Prioridad de Cliente",
"ClientPriority": "Prioridad del 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 del certificado",
"CertificateValidation": "Validacion de certificado",
"BypassProxyForLocalAddresses": "Omitir Proxy para Direcciones Locales",
"Branch": "Rama",
"BindAddressHelpText": "Dirección IP4 válida, localhost o '*' para todas las interfaces",
@@ -167,7 +167,7 @@
"URLBase": "URL Base",
"Uptime": "Tiempo de actividad",
"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 {appName} o un script",
"UpdateMechanismHelpText": "Usar el actualizador incorporado de {appName} 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",
"UnableToLoadNotifications": "No se pueden cargar las Notificaciones",
@@ -236,13 +236,13 @@
"ExistingTag": "Etiqueta existente",
"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 {appName}",
"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}'?",
"CancelPendingTask": "Seguro que quieres cancelar esta tarea pendiente?",
"BranchUpdateMechanism": "Rama usada por el mecanismo de actualización externo",
"BranchUpdate": "Qué rama usar para actualizar {appName}",
"DeleteTagMessageText": "¿Está seguro de querer eliminar la etiqueta '{label}'?",
"DeleteNotificationMessageText": "¿Seguro que quieres eliminar la notificación '{name}'?",
"DeleteBackupMessageText": "Seguro que quieres eliminar la copia de seguridad '{name}'?",
"DeleteDownloadClientMessageText": "Seguro que quieres eliminar el gestor de descargas '{name}'?",
"CancelPendingTask": "Estas seguro de que deseas cancelar esta tarea pendiente?",
"BranchUpdateMechanism": "La rama se uso por un mecanisco de actualizacion externo",
"BranchUpdate": "Rama a usar para actualizar {appName}",
"BeforeUpdate": "Antes de actualizar",
"AddingTag": "Añadir etiqueta",
"UnableToLoadUISettings": "No se han podido cargar los ajustes de UI",
@@ -256,12 +256,12 @@
"StartTypingOrSelectAPathBelow": "Comienza a escribir o selecciona una ruta debajo",
"Restore": "Restaurar",
"ProwlarrSupportsAnyIndexer": "{appName} 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.",
"ProwlarrSupportsAnyDownloadClient": "{appName} soporta cualquier gestor de descargas indicado 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",
"MaintenanceRelease": "Lanzamiento de mantenimiento",
"MaintenanceRelease": "Lanzamiento de mantenimiento: Corrección de errores y otras mejoras. Ver historial de commits de Github para mas detalle",
"ForMoreInformationOnTheIndividualDownloadClients": "Para más información individual de los gestores de descarga, haz clic en lls botones de información.",
"FilterPlaceHolder": "Buscar películas",
"Exception": "Excepción",
@@ -288,7 +288,7 @@
"IndexerLongTermStatusCheckAllClientMessage": "Ningún indexer está disponible por errores durando más de 6 horas",
"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}'?",
"DeleteIndexerProxyMessageText": "¿Seguro que quieres eliminar el proxy indexador '{name}'?",
"Discord": "Discord",
"Add": "Añadir",
"Custom": "Personalizado",
@@ -307,7 +307,7 @@
"ApplicationStatusCheckAllClientMessage": "Las listas no están disponibles debido a errores",
"ApplicationStatusCheckSingleClientMessage": "Listas no disponibles debido a errores: {0}",
"AllIndexersHiddenDueToFilter": "Todos los indexadores están ocultas debido al filtro aplicado.",
"DeleteApplicationMessageText": "Seguro que quieres elminiar la notificación '{0}'?",
"DeleteApplicationMessageText": "Seguro que quieres eliminar la notificación '{name}'?",
"IndexerProxyStatusCheckAllClientMessage": "Los indexers no están disponibles debido a errores",
"IndexerProxyStatusCheckSingleClientMessage": "Indexers no disponibles debido a errores: {0}",
"NoLinks": "Sin enlaces",
@@ -333,7 +333,7 @@
"Applications": "Aplicaciones",
"AppProfileInUse": "Perfil de aplicación en uso",
"AddDownloadClientToProwlarr": "Añadir un cliente de descargas permite a {appName} enviar descargas directamente desde la interfaz en una búsqueda manual.",
"Category": "Categoría",
"Category": "Categoria",
"Application": "Aplicación",
"BookSearch": "Búsqueda de libros",
"BookSearchTypes": "Tipos de búsqueda de libros",
@@ -375,14 +375,14 @@
"ApplyTagsHelpTextAdd": "Añadir: Añadir a las etiquetas la lista existente de etiquetas",
"DeleteSelectedApplicationsMessageText": "Seguro que quieres eliminar el indexer '{0}'?",
"DeleteSelectedDownloadClients": "Borrar Gestor de Descargas",
"DeleteSelectedIndexersMessageText": "Seguro que quieres eliminar el indexer '{0}'?",
"DeleteSelectedDownloadClientsMessageText": "¿Está seguro de querer eliminar {0} cliente(s) de descarga seleccionado(s)?",
"DeleteSelectedIndexersMessageText": "¿Está seguro de querer eliminar {count} indexador(es) seleccionado(s)?",
"DeleteSelectedDownloadClientsMessageText": "¿Está seguro de querer eliminar {count} cliente(s) de descarga seleccionado(s)?",
"ApplyTagsHelpTextHowToApplyApplications": "Cómo añadir etiquetas a las películas seleccionadas",
"SelectIndexers": "Buscar películas",
"ApplyTagsHelpTextHowToApplyIndexers": "Cómo añadir etiquetas a los indexadores seleccionados",
"ApplyTagsHelpTextRemove": "Eliminar: Eliminar las etiquetas introducidas",
"ApplyTagsHelpTextReplace": "Reemplazar: Reemplazar las etiquetas con las etiquetas introducidas (no introducir etiquetas para eliminar todas las etiquetas)",
"ThemeHelpText": "Cambia el tema de la interfaz de usuario de la aplicación. El tema \"automático\" utilizará el tema de tu sistema operativo para establecer el modo claro u oscuro. Inspirado por Theme.Park",
"ThemeHelpText": "Cambia el tema de la interfaz de usuario de la aplicación. El tema \"automático\" utilizará el tema de tu sistema operativo para establecer el modo claro u oscuro. Inspirado por {inspiredBy}.",
"DownloadClientPriorityHelpText": "Priorizar múltiples Gestores de Descargas. Se usa Round-Robin para gestores con la misma prioridad.",
"Season": "Temporada",
"More": "Más",
@@ -393,8 +393,8 @@
"Publisher": "Editor",
"AuthenticationRequired": "Autenticación requerida",
"ApplyChanges": "Aplicar Cambios",
"CountIndexersSelected": "{0} indexador(es) seleccionado(s)",
"CountDownloadClientsSelected": "{0} cliente(s) de descarga seleccionado(s)",
"CountIndexersSelected": "{count} indexador(es) seleccionado(s)",
"CountDownloadClientsSelected": "{count} cliente(s) de descarga seleccionado(s)",
"EditSelectedDownloadClients": "Editar Clientes de Descarga Seleccionados",
"EditSelectedIndexers": "Editar Indexadores Seleccionados",
"Implementation": "Implementación",
@@ -405,7 +405,7 @@
"ConnectionLostReconnect": "Radarr intentará conectarse automáticamente, o haz clic en el botón de recarga abajo.",
"ConnectionLostToBackend": "Radarr ha perdido su conexión con el backend y tendrá que ser recargado para recuperar su funcionalidad.",
"RecentChanges": "Cambios recientes",
"WhatsNew": "¿Qué hay de nuevo?",
"WhatsNew": "Que es lo nuevo?",
"minutes": "Minutos",
"Album": "álbum",
"Artist": "artista",
@@ -413,7 +413,7 @@
"AddConnection": "Añadir Conexión",
"NotificationStatusAllClientHealthCheckMessage": "Las listas no están disponibles debido a errores",
"NotificationStatusSingleClientHealthCheckMessage": "Listas no disponibles debido a errores: {0}",
"EditIndexerImplementation": "Agregar Condición - { implementationName}",
"EditIndexerImplementation": "Editar indexador - {implementationName}",
"AuthBasic": "Básico (ventana emergente del navegador)",
"AuthForm": "Formularios (página de inicio de sesión)",
"Author": "Autor",
@@ -441,5 +441,56 @@
"AuthenticationRequiredWarning": "Para evitar el acceso remoto sin autenticación, {appName} ahora requiere que la autenticación esté habilitada. Opcionalmente puede desactivar la autenticación desde una dirección local.",
"EditDownloadClientImplementation": "Añadir Cliente de Descarga - {implementationName}",
"DefaultNameCopiedProfile": "{name} - Copia",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Confirma la nueva contraseña"
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Confirma la nueva contraseña",
"NoHistoryFound": "No se encontró historial",
"DeleteApplication": "Eliminar Aplicación",
"AreYouSureYouWantToDeleteCategory": "Esta seguro que desea eliminar la categoría mapeada?",
"AdvancedSettingsHiddenClickToShow": "Configuraciones avanzadas escondidas, click para mostrar",
"AdvancedSettingsShownClickToHide": "Se muestran las configuraciones avanzadas, click para esconder",
"AppsMinimumSeeders": "Semillas mínimas para las Aplicaciones",
"ClearHistoryMessageText": "Esta seguro que desea borrar todo el historial de {appName}?",
"ClearHistory": "Borrar Historial",
"AreYouSureYouWantToDeleteIndexer": "Esta seguro que desea eliminar '{name}' de {appName}?",
"AuthQueries": "Consultas de Autorización",
"ApplicationTagsHelpText": "Sincronizar los Indexadores a esta aplicación que no tengan etiquetas o que tengan al menos una etiqueta coincidente",
"ApplicationTagsHelpTextWarning": "Las etiquetas deben utilizarse con cuidado, pueden tener efectos involuntarios. Una aplicación con una etiqueta solo sincronizara con Indexadores que tengan la misma etiqueta.",
"AppsMinimumSeedersHelpText": "Cantidad mínima de semillas requerida por las Aplicaciones para que el Indexador capture, vacío aplica la configuración por defecto del perfil",
"AverageResponseTimesMs": "Tiempo promedio de respuesta del Indexador (ms)",
"CountIndexersAvailable": "{count} indexadores disponibles",
"DeleteAppProfile": "Eliminar Perfil de Aplicación",
"AddSyncProfile": "Agregar Perfil de Sincronización",
"AppSettingsSummary": "Aplicaciones y configuraciones para determinar como {appName} interactúa con sus programas de PVR",
"AddCategory": "Agregar Categoría",
"AppProfileSelectHelpText": "Los perfiles de la aplicación se usan para controlar la configuración por aplicación de RSS, Búsqueda Automática y Búsqueda Interactiva",
"ActiveApps": "Aplicaciones Activas",
"ActiveIndexers": "Indexadores Activos",
"AudioSearch": "Búsqueda de Música",
"Auth": "Autenticación",
"BasicSearch": "Búsqueda Básica",
"CountApplicationsSelected": "{count} aplicaciones seleccionadas",
"IndexerHealthCheckNoIndexers": "Ningún indexador habilitado, {appName} no devolverá resultados de búsqueda",
"IndexerAuth": "Autentificación de indexador",
"DeleteSelectedApplications": "Eliminar aplicaciones seleccionadas",
"DeleteSelectedIndexer": "Eliminar indexador seleccionado",
"IndexerCategories": "Categorías de indexador",
"IndexerDownloadClientHelpText": "Especifique qué cliente de descarga se utiliza para capturas hechas desde {appName} a partir de este indexador",
"FullSync": "Sincronización total",
"GoToApplication": "Ir a la aplicación",
"FoundCountReleases": "{itemCount} releases hallados",
"HistoryDetails": "Detalles de historial",
"DeleteClientCategory": "Eliminar categoría de cliente de descarga",
"DeleteSelectedIndexers": "Eliminar indexadores seleccionados",
"DevelopmentSettings": "Ajustes de desarrollo",
"EnabledRedirected": "Habilitado, redireccionado",
"IndexerDetails": "Detalles de indexador",
"IndexerDisabled": "Indexador deshabilitado",
"IndexerFailureRate": "Tasa de fallo del indexador",
"IndexerAlreadySetup": "Hay al menos una instancia de indexador configurada",
"DisabledUntil": "Deshabilitado hasta",
"DownloadClientCategory": "Categoría de cliente de descarga",
"HistoryCleanup": "Limpieza de historial",
"Id": "Id",
"EditCategory": "Editar categoría",
"EditSyncProfile": "Editar perfil de sincronización",
"EnableIndexer": "Habilitar indexador"
}

View File

@@ -3,7 +3,7 @@
"Indexers": "Indexeurs",
"Host": "Hôte",
"History": "Historique",
"HideAdvanced": "Masquer param. av.",
"HideAdvanced": "Masquer les Options Avancées",
"Health": "Santé",
"General": "Général",
"Folder": "Dossier",
@@ -12,7 +12,7 @@
"Events": "Événements",
"Edit": "Modifier",
"DownloadClientStatusCheckAllClientMessage": "Aucun client de téléchargement n'est disponible en raison d'échecs",
"DownloadClients": "Clients de télécharg.",
"DownloadClients": "Clients de téléchargement",
"Dates": "Dates",
"Date": "Date",
"Delete": "Supprimer",
@@ -207,7 +207,7 @@
"ProxyBypassFilterHelpText": "Utilisez ',' comme séparateur et '*.' comme caractère générique pour les sous-domaines",
"Uptime": "Disponibilité",
"UpdateScriptPathHelpText": "Chemin d'accès à un script personnalisé qui prend un package de mise à jour extrait et gère le reste du processus de mise à jour",
"UpdateMechanismHelpText": "Utiliser le programme de mise à jour intégré de {appName} ou un script",
"UpdateMechanismHelpText": "Utilisez le programme de mise à jour intégré de {appName} ou un script",
"UpdateAutomaticallyHelpText": "Téléchargez et installez automatiquement les mises à jour. Vous pourrez toujours installer à partir du système : mises à jour",
"UnableToLoadUISettings": "Impossible de charger les paramètres de l'interface utilisateur",
"UnableToLoadTags": "Impossible de charger les étiquettes",

View File

@@ -19,7 +19,7 @@
"ChangeHasNotBeenSavedYet": "Perubahan belum disimpan",
"EnableInteractiveSearch": "Aktifkan Penelusuran Interaktif",
"Ended": "Berakhir",
"AuthenticationMethodHelpText": "Perlukan Nama Pengguna dan Sandi untuk mengakses Radarr",
"AuthenticationMethodHelpText": "Perlukan Nama Pengguna dan Sandi untuk mengakses {appName}",
"Host": "Host",
"Enable": "Aktif",
"EnableRss": "Aktifkan RSS",
@@ -34,7 +34,7 @@
"Categories": "Kategori",
"Close": "Tutup",
"ConnectionLost": "Koneksi Terputus",
"Connections": "Koleksi",
"Connections": "Koneksi",
"Custom": "Khusus",
"Dates": "Tanggal",
"Delete": "Hapus",
@@ -46,7 +46,7 @@
"Hostname": "Hostname",
"Info": "Informasi",
"Language": "Bahasa",
"LogFiles": "Berkas Log",
"LogFiles": "File Log",
"NoChange": "Tidak Ada Perubahan",
"NoChanges": "Tidak Ada Perubahan",
"Queued": "Antrean",
@@ -58,7 +58,25 @@
"Actions": "Tindakan",
"AllIndexersHiddenDueToFilter": "Semua film disembunyikan karena penyaringan yang diterapkan.",
"AnalyticsEnabledHelpText": "Kirimkan informasi penggunaan secara anonim ke server Radarr. Informasi tersebut mengandung browser kamu, halaman WebUI Radarr yang kamu gunakan, pelaporan masalah serta OS dan versi runtime. Kami akan memanfaatkan informasi ini untuk memprioritaskan fitur dan perbaikan bug.",
"ConnectionLostReconnect": "Radarr akan mencoba untuk menghubungi secara otomatis, atau klik muat ulang di bawah.",
"ConnectionLostReconnect": "{appName} akan mencoba untuk menghubungkan secara otomatis, atau silakan klik muat ulang di bawah.",
"AuthBasic": "Dasar (Popup Browser)",
"AuthForm": "Formulir (Halaman Login)"
"AuthForm": "Formulir (Halaman Masuk)",
"Category": "Kategori",
"ApplyChanges": "Terapkan Perubahan",
"Today": "Hari Ini",
"Yesterday": "Kemarin",
"Search": "Cari",
"ConnectSettings": "Pengaturan Koneksi",
"Refresh": "Muat Ulang",
"ConnectionLostToBackend": "Koneksi {appName} telah terputus dari backend dan perlu dimuat ulang untuk dipulihkan.",
"Edit": "Edit",
"Files": "File",
"History": "Riwayat",
"AuthenticationMethod": "Metode Autentikasi",
"AuthenticationMethodHelpTextWarning": "Silakan pilih metode autentikasi yang sah",
"AuthenticationRequired": "Autentikasi Diperlukan",
"AuthenticationRequiredPasswordHelpTextWarning": "Masukkan sandi baru",
"AuthenticationRequiredUsernameHelpTextWarning": "Masukkan nama pengguna baru",
"AuthenticationRequiredWarning": "Untuk mencegah akses jarak jauh tanpa autentikasi, {appName} kini mewajibkan pengaktifkan autentikasi. Kamu dapat menonaktifkan autentikasi dari jaringan lokal.",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "Konfirmasi sandi baru"
}

View File

@@ -1 +1,9 @@
{}
{
"About": "Par",
"AcceptConfirmationModal": "Apstiprināt Apstiprināšanas Modālu",
"Actions": "Darbības",
"Add": "Pievienot",
"AddDownloadClient": "Pievienot Lejupielādes Klientu",
"AddConnection": "Pievienot Savienojumu",
"AddConnectionImplementation": "Pievienot Savienojumu - {implementationName}"
}

View File

@@ -90,9 +90,9 @@
"DeleteApplication": "Applicatie verwijderen",
"DeleteApplicationMessageText": "Weet u zeker dat u de applicatie '{0}' wilt verwijderen?",
"DeleteBackup": "Verwijder Backup",
"DeleteBackupMessageText": "Bent u zeker dat u de veiligheidskopie '{0}' wilt verwijderen?",
"DeleteBackupMessageText": "Bent u zeker dat u de veiligheidskopie '{name}' wilt verwijderen?",
"DeleteDownloadClient": "Verwijder Downloader",
"DeleteDownloadClientMessageText": "Bent u zeker dat u de downloader '{0}' wilt verwijderen?",
"DeleteDownloadClientMessageText": "Bent u zeker dat u de downloader '{name}' wilt verwijderen?",
"DeleteIndexerProxy": "Indexeerproxy verwijderen",
"DeleteIndexerProxyMessageText": "Weet u zeker dat u de proxy '{0}' wilt verwijderen?",
"DeleteNotification": "Verwijder Notificatie",
@@ -425,7 +425,7 @@
"ApplyTagsHelpTextHowToApplyIndexers": "Hoe tags toepassen op de geselecteerde indexeerders",
"ApplyTagsHelpTextRemove": "Verwijderen: Verwijder de ingevoerde tags",
"ApplyTagsHelpTextReplace": "Vervangen: Vervang de tags met de ingevoerde tags (vul geen tags in om alle tags te wissen)",
"CountIndexersSelected": "{0} Indexer(s) Geselecteerd",
"CountIndexersSelected": "{count} Indexer(s) Geselecteerd",
"DeleteSelectedApplicationsMessageText": "Bent u zeker dat u de indexeerder '{0}' wilt verwijderen?",
"DeleteSelectedDownloadClients": "Verwijder Downloader",
"DeleteSelectedDownloadClientsMessageText": "Bent u zeker dat u de indexeerder '{0}' wilt verwijderen?",
@@ -458,7 +458,7 @@
"None": "Geen",
"ResetAPIKeyMessageText": "Bent u zeker dat u uw API-sleutel wilt resetten?",
"AddConnectionImplementation": "Voeg connectie toe - {implementationName}",
"AddDownloadClientImplementation": "Voeg Downloadclient toe - {implementationName}",
"AddDownloadClientImplementation": "Voeg Downloadclient Toe - {implementationName}",
"AddIndexerImplementation": "Indexeerder toevoegen - {implementationName}",
"AdvancedSettingsHiddenClickToShow": "Geavanceerde instellingen zijn verborgen, klik om te tonen",
"AdvancedSettingsShownClickToHide": "Geavanceerde instellingen worden getoond, klik om te verbergen",
@@ -473,5 +473,8 @@
"AddApplicationImplementation": "Voeg connectie toe - {implementationName}",
"AddIndexerProxyImplementation": "Indexeerder toevoegen - {implementationName}",
"EditApplicationImplementation": "Voeg connectie toe - {implementationName}",
"EditIndexerProxyImplementation": "Indexeerder toevoegen - {implementationName}"
"EditIndexerProxyImplementation": "Indexeerder toevoegen - {implementationName}",
"AuthenticationMethod": "Authenticatiemethode",
"AuthenticationRequired": "Verificatie vereist",
"AuthenticationMethodHelpTextWarning": "Selecteer een geldige verificatie methode"
}

View File

@@ -479,7 +479,7 @@
"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}'.",
"UpdateCheckStartupTranslocationMessage": "Não é possível instalar a atualização porque a pasta de inicialização '{0}' está em uma pasta de translocação de aplicativo.",
"UpdateCheckUINotWritableMessage": "Não é possível instalar a atualização porque a pasta de IU '{0}' não pode ser gravada pelo usuário '{1}'.",
"UpdateMechanismHelpText": "Usar o atualizador integrado do {appName} ou um script",
"UpdateMechanismHelpText": "Use o atualizador integrado do {appName} ou um script",
"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",
"Updates": "Atualizações",
"Uptime": "Tempo de atividade",

View File

@@ -360,12 +360,5 @@
"Categories": "Kategoriler",
"Application": "Uygulamalar",
"Episode": "bölüm",
"AddApplicationImplementation": "Koşul Ekle - {uygulama Adı}",
"AddConnection": "Bağlantı Ekle",
"AddConnectionImplementation": "Koşul Ekle - {uygulama Adı}",
"AddIndexerImplementation": "Koşul Ekle - {uygulama Adı}",
"AddIndexerProxyImplementation": "Koşul Ekle - {uygulama Adı}",
"EditConnectionImplementation": "Koşul Ekle - {uygulama Adı}",
"EditApplicationImplementation": "Koşul Ekle - {uygulama Adı}",
"EditIndexerImplementation": "Koşul Ekle - {uygulama Adı}"
"AddConnection": "Bağlantı Ekle"
}

View File

@@ -21,7 +21,7 @@
"AllIndexersHiddenDueToFilter": "由于应用了筛选器,所有索引器都被隐藏。",
"Analytics": "分析",
"AnalyticsEnabledHelpText": "将匿名使用情况和错误信息发送到{appName}的服务器。这包括有关您的浏览器的信息、您使用的{appName} WebUI页面、错误报告以及操作系统和运行时版本。我们将使用此信息来确定功能和错误修复的优先级。",
"ApiKey": "API Key",
"ApiKey": "接口密钥 (API Key)",
"ApiKeyValidationHealthCheckMessage": "请将API密钥更新为至少{0}个字符长。您可以通过设置或配置文件执行此操作",
"AppDataDirectory": "AppData目录",
"AppDataLocationHealthCheckMessage": "正在更新期间的 AppData 不会被更新删除",
@@ -46,7 +46,7 @@
"Authentication": "认证",
"AuthenticationMethodHelpText": "需要用户名和密码以访问 {appName}",
"AuthenticationRequired": "需要身份验证",
"AuthenticationRequiredHelpText": "更改身份验证的请求。除非了解风险,否则请勿更改。",
"AuthenticationRequiredHelpText": "修改哪些请求需要认证。除非了解其中的风险,否则不要更改。",
"AuthenticationRequiredWarning": "为了防止未经身份验证的远程访问,{appName} 现在需要启用身份验证。您可以禁用本地地址的身份验证。",
"Author": "作者",
"Automatic": "自动化",
@@ -139,7 +139,7 @@
"EnableInteractiveSearchHelpText": "当手动搜索启用时使用",
"EnableRss": "启用RSS",
"EnableRssHelpText": "为搜刮器启用 RSS订阅",
"EnableSSL": "启用SSL",
"EnableSSL": "启用 SSL",
"EnableSslHelpText": " 重启生效",
"Enabled": "已启用",
"EnabledRedirected": "启用, 修改",
@@ -469,7 +469,7 @@
"UpdateCheckStartupNotWritableMessage": "无法安装更新,因为用户“{1}”对于启动文件夹“{0}”没有写入权限。",
"UpdateCheckStartupTranslocationMessage": "无法安装更新,因为启动文件夹“{0}”在一个应用程序迁移文件夹。Cannot install update because startup folder '{0}' is in an App Translocation folder.",
"UpdateCheckUINotWritableMessage": "无法安装升级,因为用户“{1}”不可写入界面文件夹“{0}”。",
"UpdateMechanismHelpText": "使用 {appName} 内置的更新器或者脚本",
"UpdateMechanismHelpText": "使用 {appName} 内置的更新程序或脚本",
"UpdateScriptPathHelpText": "自定义脚本的路径,该脚本处理获取的更新包并处理更新过程的其余部分",
"Updates": "更新",
"Uptime": "运行时间",
@@ -597,5 +597,8 @@
"ActiveIndexers": "活动索引器",
"ActiveApps": "活动应用程序",
"AppsMinimumSeeders": "应用程序最少种子数",
"PackSeedTime": "做种时间"
"PackSeedTime": "做种时间",
"PasswordConfirmation": "确认密码",
"AuthenticationRequiredPasswordConfirmationHelpTextWarning": "确认新密码",
"InvalidUILanguage": "语言"
}

View File

@@ -93,14 +93,6 @@ namespace NzbDrone.Core.Notifications.CustomScript
failures.Add(new NzbDroneValidationFailure("Path", "File does not exist"));
}
foreach (var systemFolder in SystemFolders.GetSystemFolders())
{
if (systemFolder.IsParentPath(Settings.Path))
{
failures.Add(new NzbDroneValidationFailure("Path", $"Must not be a descendant of '{systemFolder}'"));
}
}
if (failures.Empty())
{
try

View File

@@ -11,6 +11,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
public CustomScriptSettingsValidator()
{
RuleFor(c => c.Path).IsValidPath();
RuleFor(c => c.Path).SetValidator(new SystemFolderValidator()).WithMessage("Must not be a descendant of '{systemFolder}'");
RuleFor(c => c.Arguments).Empty().WithMessage("Arguments are no longer supported for custom scripts");
}
}

View File

@@ -65,6 +65,11 @@ namespace NzbDrone.Core.Notifications.Discord
discordField.Name = "Host";
discordField.Value = message.Host ?? string.Empty;
break;
case DiscordGrabFieldType.Size:
discordField.Name = "Size";
discordField.Value = BytesToString(message.Release.Size.GetValueOrDefault(0));
discordField.Inline = true;
break;
}
if (discordField.Name.IsNotNullOrWhiteSpace() && discordField.Value.IsNotNullOrWhiteSpace())

View File

@@ -7,6 +7,7 @@ namespace NzbDrone.Core.Notifications.Discord
DownloadClient,
GrabTrigger,
Source,
Host
Host,
Size
}
}

View File

@@ -19,10 +19,19 @@ namespace NzbDrone.Core.Notifications.Discord
public DiscordSettings()
{
//Set Default Fields
GrabFields = new List<int> { 0, 1, 2, 3, 5, 6, 7, 8, 9 };
GrabFields = new List<int>
{
(int)DiscordGrabFieldType.Release,
(int)DiscordGrabFieldType.Indexer,
(int)DiscordGrabFieldType.DownloadClient,
(int)DiscordGrabFieldType.GrabTrigger,
(int)DiscordGrabFieldType.Source,
(int)DiscordGrabFieldType.Host,
(int)DiscordGrabFieldType.Size
};
}
private static readonly DiscordSettingsValidator Validator = new DiscordSettingsValidator();
private static readonly DiscordSettingsValidator Validator = new ();
[FieldDefinition(0, Label = "Webhook URL", HelpText = "Discord channel webhook url")]
public string WebHookUrl { get; set; }
@@ -36,7 +45,7 @@ namespace NzbDrone.Core.Notifications.Discord
[FieldDefinition(3, Label = "Host", Advanced = true, HelpText = "Override the Host that shows for this notification, Blank is machine name", Type = FieldType.Textbox)]
public string Author { get; set; }
[FieldDefinition(4, Label = "On Grab Fields", Advanced = true, SelectOptions = typeof(DiscordGrabFieldType), HelpText = "Change the fields that are passed in for this 'on grab' notification", Type = FieldType.TagSelect)]
[FieldDefinition(4, Label = "On Grab Fields", Advanced = true, SelectOptions = typeof(DiscordGrabFieldType), HelpText = "Change the fields that are passed in for this 'on grab' notification", Type = FieldType.Select)]
public IEnumerable<int> GrabFields { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -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.9" />
<PackageReference Include="MonoTorrent" Version="2.0.7" />
<PackageReference Include="YamlDotNet" Version="13.7.1" />
<PackageReference Include="YamlDotNet" Version="13.1.1" />
<PackageReference Include="AngleSharp" Version="1.0.6" />
</ItemGroup>
<ItemGroup>

View File

@@ -23,8 +23,10 @@ namespace Prowlarr.Api.V1.Search
public string ReleaseHash { get; set; }
public string Title { get; set; }
public string SortTitle { get; set; }
public bool Approved { get; set; }
public int ImdbId { get; set; }
public int TmdbId { get; set; }
public int TvdbId { get; set; }
public int TvMazeId { get; set; }
public DateTime PublishDate { get; set; }
public string CommentUrl { get; set; }
public string DownloadUrl { get; set; }
@@ -80,6 +82,9 @@ namespace Prowlarr.Api.V1.Search
Title = releaseInfo.Title,
SortTitle = releaseInfo.Title.NormalizeTitle(),
ImdbId = releaseInfo.ImdbId,
TmdbId = releaseInfo.TmdbId,
TvdbId = releaseInfo.TvdbId,
TvMazeId = releaseInfo.TvMazeId,
PublishDate = releaseInfo.PublishDate,
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,

View File

@@ -5751,13 +5751,22 @@
"type": "string",
"nullable": true
},
"approved": {
"type": "boolean"
},
"imdbId": {
"type": "integer",
"format": "int32"
},
"tmdbId": {
"type": "integer",
"format": "int32"
},
"tvdbId": {
"type": "integer",
"format": "int32"
},
"tvMazeId": {
"type": "integer",
"format": "int32"
},
"publishDate": {
"type": "string",
"format": "date-time"