1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-06 13:31:28 -05:00

Compare commits

..

1 Commits

Author SHA1 Message Date
ta264
7641190475 Test postgres in non-UTC docker 2022-07-17 11:38:54 +01:00
67 changed files with 1195 additions and 3249 deletions

View File

@@ -1,6 +1,7 @@
{
"paths": [
"frontend/src/**/*.js"
"frontend/src/**/*.js",
"src/NzbDrone.Core/Localization/Core/*.json"
],
"ignored": [
"**/node_modules/**/*"

View File

@@ -9,13 +9,13 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '4.2.2'
majorVersion: '4.2.0'
minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.400'
dotnetVersion: '6.0.300'
nodeVersion: '16.X'
innoVersion: '6.2.0'
windowsImage: 'windows-2022'
@@ -549,7 +549,7 @@ stages:
Radarr__Postgres__Password: 'radarr'
pool:
vmImage: ${{ variables.linuxImage }}
vmImage: 'ubuntu-18.04'
timeoutInMinutes: 10
@@ -687,7 +687,7 @@ stages:
Radarr__Postgres__Password: 'radarr'
pool:
vmImage: ${{ variables.linuxImage }}
vmImage: 'ubuntu-18.04'
steps:
- task: UseDotNet@2

View File

@@ -116,7 +116,7 @@ export const filterPredicates = {
const predicate = filterTypePredicates[type];
const { collection } = item;
return predicate(collection ? collection.title : '', filterValue);
return predicate(collection ? collection.name : '', filterValue);
},
originalLanguage: function(item, filterValue, type) {

View File

@@ -165,11 +165,11 @@ export const actionHandlers = handleThunks({
requestData.quality = quality;
}
if (releaseGroup !== undefined) {
if (releaseGroup) {
requestData.releaseGroup = releaseGroup;
}
if (edition !== undefined) {
if (edition) {
requestData.edition = edition;
}
@@ -201,11 +201,11 @@ export const actionHandlers = handleThunks({
props.quality = quality;
}
if (edition !== undefined) {
if (edition) {
props.edition = edition;
}
if (releaseGroup !== undefined) {
if (releaseGroup) {
props.releaseGroup = releaseGroup;
}

View File

@@ -341,8 +341,8 @@ export const defaultState = {
const collectionList = items.reduce((acc, movie) => {
if (movie.collection) {
acc.push({
id: movie.collection.title,
name: movie.collection.title
id: movie.collection.name,
name: movie.collection.name
});
}

View File

@@ -30,7 +30,7 @@
"@fortawesome/free-regular-svg-icons": "6.1.0",
"@fortawesome/free-solid-svg-icons": "6.1.0",
"@fortawesome/react-fontawesome": "0.1.18",
"@microsoft/signalr": "6.0.8",
"@microsoft/signalr": "6.0.5",
"@sentry/browser": "6.18.2",
"@sentry/integrations": "6.18.2",
"classnames": "2.3.1",

View File

@@ -90,7 +90,7 @@
<!-- Standard testing packages -->
<ItemGroup Condition="'$(TestProject)'=='true'">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageReference Include="NunitXml.TestLogger" Version="3.0.117" />

View File

@@ -8,6 +8,5 @@
<add key="SQLite" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/SQLite/nuget/v3/index.json" />
<add key="coverlet-nightly" value="https://pkgs.dev.azure.com/Servarr/coverlet/_packaging/coverlet-nightly/nuget/v3/index.json" />
<add key="FFMpegCore" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/FFMpegCore/nuget/v3/index.json" />
<add key="FluentMigrator" value="https://pkgs.dev.azure.com/Servarr/Servarr/_packaging/FluentMigrator/nuget/v3/index.json" />
</packageSources>
</configuration>

View File

@@ -20,21 +20,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
private static Exception[] FilteredExceptions = new Exception[]
{
new UnauthorizedAccessException(),
new AggregateException(new Exception[]
{
new UnauthorizedAccessException(),
new UnauthorizedAccessException()
})
};
private static Exception[] NonFilteredExceptions = new Exception[]
{
new AggregateException(new Exception[]
{
new UnauthorizedAccessException(),
new NotImplementedException()
})
new UnauthorizedAccessException()
};
[SetUp]
@@ -77,14 +63,6 @@ namespace NzbDrone.Common.Test.InstrumentationTests
_subject.IsSentryMessage(log).Should().BeFalse();
}
[Test]
[TestCaseSource("NonFilteredExceptions")]
public void should_not_filter_event_for_filtered_exception_types(Exception ex)
{
var log = GivenLogEvent(LogLevel.Error, ex, "test");
_subject.IsSentryMessage(log).Should().BeTrue();
}
[Test]
[TestCaseSource("FilteredExceptions")]
public void should_not_filter_event_for_filtered_exception_types_if_filtering_disabled(Exception ex)

View File

@@ -18,7 +18,7 @@ namespace NzbDrone.Common.Instrumentation
new Regex(@"iptorrents\.com/[/a-z0-9?&;]*?(?:[?&;](u|tp)=(?<secret>[^&=;]+?))+(?= |;|&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"/fetch/[a-z0-9]{32}/(?<secret>[a-z0-9]{32})", RegexOptions.Compiled),
new Regex(@"getnzb.*?(?<=\?|&)(r)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"\b[^;=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=[?& ;])[^=]*?(_?(?<!use|get_)token|username|passwo?rd)=(?<secret>[^&=]+?)(?= |&|$|;)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
// Trackers Announce Keys; Designed for Qbit Json; should work for all in theory
new Regex(@"announce(\.php)?(/|%2f|%3fpasskey%3d)(?<secret>[a-z0-9]{16,})|(?<secret>[a-z0-9]{16,})(/|%2f)announce"),

View File

@@ -229,48 +229,21 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
if (FilterEvents)
{
var exceptions = new List<Exception>();
var aggEx = logEvent.Exception as AggregateException;
if (aggEx != null && aggEx.InnerExceptions.Count > 0)
var sqlEx = logEvent.Exception as SQLiteException;
if (sqlEx != null && FilteredSQLiteErrors.Contains(sqlEx.ResultCode))
{
exceptions.AddRange(aggEx.InnerExceptions);
}
else
{
exceptions.Add(logEvent.Exception);
return false;
}
// If any are sentry then send to sentry
foreach (var ex in exceptions)
if (FilteredExceptionTypeNames.Contains(logEvent.Exception.GetType().Name))
{
var isSentry = true;
var sqlEx = ex as SQLiteException;
if (sqlEx != null && !FilteredSQLiteErrors.Contains(sqlEx.ResultCode))
{
isSentry = false;
}
if (FilteredExceptionTypeNames.Contains(ex.GetType().Name))
{
isSentry = false;
}
if (FilteredExceptionMessages.Any(x => ex.Message.Contains(x)))
{
isSentry = false;
}
if (isSentry)
{
return true;
}
return false;
}
// The exception or aggregate exception children were not sentry exceptions
return false;
if (FilteredExceptionMessages.Any(x => logEvent.Exception.Message.Contains(x)))
{
return false;
}
}
return true;

View File

@@ -10,10 +10,10 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="5.0.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Sentry" Version="3.20.1" />
<PackageReference Include="Sentry" Version="3.15.0" />
<PackageReference Include="NLog.Targets.Syslog" Version="7.0.0" />
<PackageReference Include="SharpZipLib" Version="1.3.3" />
<PackageReference Include="System.Text.Json" Version="6.0.5" />
<PackageReference Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />

View File

@@ -27,20 +27,6 @@ namespace NzbDrone.Core.Test.Datastore
Mocker.Resolve<IDatabase>().Vacuum();
}
[Test]
public void postgres_should_not_contain_timestamp_without_timezone_columns()
{
if (Db.DatabaseType != DatabaseType.PostgreSQL)
{
return;
}
Mocker.Resolve<IDatabase>()
.OpenConnection().Query("SELECT table_name, column_name, data_type FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = 'public' AND data_type = 'timestamp without time zone'")
.Should()
.BeNullOrEmpty();
}
[Test]
public void get_version()
{

View File

@@ -1,67 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
[TestFixture]
public class EditionTagsFixture : CoreTest<FileNameBuilder>
{
private Movie _movie;
private MovieFile _movieFile;
private NamingConfig _namingConfig;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>
.CreateNew()
.With(s => s.Title = "South Park")
.Build();
_movieFile = new MovieFile { Quality = new QualityModel(), ReleaseGroup = "SonarrTest" };
_namingConfig = NamingConfig.Default;
_namingConfig.RenameMovies = true;
Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(_namingConfig);
Mocker.GetMock<IQualityDefinitionService>()
.Setup(v => v.Get(Moq.It.IsAny<Quality>()))
.Returns<Quality>(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v));
Mocker.GetMock<ICustomFormatService>()
.Setup(v => v.All())
.Returns(new List<CustomFormat>());
}
[Test]
public void should_add_edition_tag()
{
_movieFile.Edition = "Uncut";
_namingConfig.StandardMovieFormat = "{Movie Title} [{Edition Tags}]";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("South Park [Uncut]");
}
[TestCase("{Movie Title} {edition-{Edition Tags}}")]
public void should_conditional_hide_edition_tags_in_plex_format(string movieFormat)
{
_movieFile.Edition = "";
_namingConfig.StandardMovieFormat = movieFormat;
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("South Park");
}
}
}

View File

@@ -1,4 +1,4 @@
using FizzWare.NBuilder;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NUnit.Framework.Internal;
@@ -47,25 +47,5 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
Subject.GetMovieFolder(_movie)
.Should().Be($"Movie Title ({_movie.TmdbId})");
}
[Test]
public void should_add_imdb_tag()
{
_namingConfig.MovieFolderFormat = "{Movie Title} {imdb-{ImdbId}}";
Subject.GetMovieFolder(_movie)
.Should().Be($"Movie Title {{imdb-{_movie.ImdbId}}}");
}
[Test]
public void should_skip_imdb_tag_if_null()
{
_namingConfig.MovieFolderFormat = "{Movie Title} {imdb-{ImdbId}}";
_movie.ImdbId = null;
Subject.GetMovieFolder(_movie)
.Should().Be($"Movie Title");
}
}
}

View File

@@ -342,16 +342,6 @@ namespace NzbDrone.Core.Test.ParserTests
result.Languages.Should().BeEquivalentTo(Language.Bengali);
}
[TestCase("Movie.Title.1994.HDTV.x264.SK-iCZi")]
[TestCase("Movie.Title.2019.1080p.HDTV.x265.iNTERNAL.SK-iCZi")]
[TestCase("Movie.Title.2018.SLOVAK.DUAL.2160p.UHD.BluRay.x265-iCZi")]
[TestCase("Movie.Title.1990.SLOVAK.HDTV.x264-iCZi")]
public void should_parse_language_slovak(string postTitle)
{
var result = Parser.Parser.ParseMovieTitle(postTitle);
result.Languages.Should().BeEquivalentTo(Language.Slovak);
}
[TestCase("Movie.Title.en.sub")]
[TestCase("Movie Title.eng.sub")]
[TestCase("Movie.Title.eng.forced.sub")]

View File

@@ -100,10 +100,6 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Yet Another Anime Movie 2012 [Kametsu] [Blu-ray][MKV][h264 10-bit][1080p][FLAC 5.1][Dual Audio][Softsubs (Kametsu)]", "Kametsu")]
[TestCase("Another.Anime.Film.Name.2016.JPN.Blu-Ray.Remux.AVC.DTS-MA.BluDragon", "BluDragon")]
[TestCase("A Movie in the Name (1964) (1080p BluRay x265 r00t)", "r00t")]
[TestCase("Movie Title (2022) (2160p ATV WEB-DL Hybrid H265 DV HDR DDP Atmos 5.1 English - HONE)", "HONE")]
[TestCase("Movie Title (2009) (2160p PMTP WEB-DL Hybrid H265 DV HDR10+ DDP Atmos 5.1 English - HONE)", "HONE")]
[TestCase("Why.Cant.You.Use.Normal.Characters.2021.2160p.UHD.HDR10+.BluRay.TrueHD.Atmos.7.1.x265-ZØNEHD", "ZØNEHD")]
[TestCase("Movie.Should.Not.Use.Dots.2022.1080p.BluRay.x265.10bit.Tigole", "Tigole")]
public void should_parse_exception_release_group(string title, string expected)
{
Parser.Parser.ParseReleaseGroup(title).Should().Be(expected);

View File

@@ -1,161 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class SlugParserFixture : CoreTest
{
[TestCase("tèst", "test")]
[TestCase("têst", "test")]
[TestCase("tëst", "test")]
[TestCase("tËst", "test")]
[TestCase("áccent", "accent")]
[TestCase("àccent", "accent")]
[TestCase("âccent", "accent")]
[TestCase("Äccent", "accent")]
[TestCase("åccent", "accent")]
[TestCase("acceñt", "accent")]
[TestCase("ßtest", "test")]
[TestCase("œtest", "test")]
[TestCase("Œtest", "test")]
[TestCase("Øtest", "test")]
public void should_replace_accents(string input, string result)
{
Parser.Parser.ToUrlSlug(input).Should().Be(result);
}
[TestCase("Test'Result")]
[TestCase("Test$Result")]
[TestCase("Test(Result")]
[TestCase("Test)Result")]
[TestCase("Test*Result")]
[TestCase("Test?Result")]
[TestCase("Test/Result")]
[TestCase("Test=Result")]
[TestCase("Test\\Result")]
public void should_replace_special_characters(string input)
{
Parser.Parser.ToUrlSlug(input).Should().Be("testresult");
}
[TestCase("ThIS IS A MiXeD CaSe SensItIvE ValUe")]
public void should_lowercase_capitals(string input)
{
Parser.Parser.ToUrlSlug(input).Should().Be("this-is-a-mixed-case-sensitive-value");
}
[TestCase("test----")]
[TestCase("test____")]
[TestCase("test-_--_")]
public void should_trim_trailing_dashes_and_underscores(string input)
{
Parser.Parser.ToUrlSlug(input).Should().Be("test");
}
[TestCase("test result")]
[TestCase("test result")]
public void should_replace_spaces_with_dash(string input)
{
Parser.Parser.ToUrlSlug(input).Should().Be("test-result");
}
[TestCase("test result", "test-result")]
[TestCase("test-----result", "test-result")]
[TestCase("test_____result", "test_result")]
public void should_replace_double_occurence(string input, string result)
{
Parser.Parser.ToUrlSlug(input).Should().Be(result);
}
[TestCase("Test'Result")]
[TestCase("Test$Result")]
[TestCase("Test(Result")]
[TestCase("Test)Result")]
[TestCase("Test*Result")]
[TestCase("Test?Result")]
[TestCase("Test/Result")]
[TestCase("Test=Result")]
[TestCase("Test\\Result")]
public void should_replace_special_characters_with_dash_when_enabled(string input)
{
Parser.Parser.ToUrlSlug(input, true).Should().Be("test-result");
}
[TestCase("Test'Result")]
[TestCase("Test$Result")]
[TestCase("Test(Result")]
[TestCase("Test)Result")]
[TestCase("Test*Result")]
[TestCase("Test?Result")]
[TestCase("Test/Result")]
[TestCase("Test=Result")]
[TestCase("Test\\Result")]
public void should__not_replace_special_characters_with_dash_when_disabled(string input)
{
Parser.Parser.ToUrlSlug(input, false).Should().Be("testresult");
}
[TestCase("test----", "-_", "test")]
[TestCase("test____", "-_", "test")]
[TestCase("test-_-_", "-_", "test")]
[TestCase("test----", "-", "test")]
[TestCase("test____", "-", "test____")]
[TestCase("test-_-_", "-", "test-_-_")]
[TestCase("test----", "_", "test----")]
[TestCase("test____", "_", "test")]
[TestCase("test-_-_", "_", "test-_-")]
[TestCase("test----", "", "test----")]
[TestCase("test____", "", "test____")]
[TestCase("test-_-_", "", "test-_-_")]
public void should_trim_trailing_dashes_and_underscores_based_on_list(string input, string trimList, string result)
{
Parser.Parser.ToUrlSlug(input, false, trimList, "").Should().Be(result);
}
[TestCase("test----result", "-_", "test-result")]
[TestCase("test____result", "-_", "test_result")]
[TestCase("test_-_-result", "-_", "test-result")]
[TestCase("test-_-_result", "-_", "test_result")]
[TestCase("test----result", "-", "test-result")]
[TestCase("test____result", "-", "test____result")]
[TestCase("test-_-_result", "-", "test-_-_result")]
[TestCase("test----result", "_", "test----result")]
[TestCase("test____result", "_", "test_result")]
[TestCase("test-_-_result", "_", "test-_-_result")]
[TestCase("test----result", "", "test----result")]
[TestCase("test____result", "", "test____result")]
[TestCase("test-_-_result", "", "test-_-_result")]
public void should_replace_duplicate_characters_based_on_list(string input, string deduplicateChars, string result)
{
Parser.Parser.ToUrlSlug(input, false, "", deduplicateChars).Should().Be(result);
}
[Test]
public void should_handle_null_trim_parameters()
{
Parser.Parser.ToUrlSlug("test", false, null, "-_").Should().Be("test");
}
[Test]
public void should_handle_null_dedupe_parameters()
{
Parser.Parser.ToUrlSlug("test", false, "-_", null).Should().Be("test");
}
[Test]
public void should_handle_empty_trim_parameters()
{
Parser.Parser.ToUrlSlug("test", false, "", "-_").Should().Be("test");
}
[Test]
public void should_handle_empty_dedupe_parameters()
{
Parser.Parser.ToUrlSlug("test", false, "-_", "").Should().Be("test");
}
}
}

View File

@@ -8,7 +8,6 @@ using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Movies;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Test.Framework;
@@ -152,107 +151,5 @@ namespace NzbDrone.Core.Test.RootFolderTests
unmappedFolders.Count.Should().BeGreaterThan(0);
unmappedFolders.Should().NotContain(u => u.Name == subFolder);
}
[TestCase("")]
[TestCase(null)]
public void should_handle_non_configured_recycle_bin(string recycleBinPath)
{
var rootFolder = Builder<RootFolder>.CreateNew()
.With(r => r.Path = @"C:\Test\TV")
.Build();
if (OsInfo.IsNotWindows)
{
rootFolder = Builder<RootFolder>.CreateNew()
.With(r => r.Path = @"/Test/TV")
.Build();
}
var subFolders = new[]
{
"Series1",
"Series2",
"Series3"
};
var folders = subFolders.Select(f => Path.Combine(@"C:\Test\TV", f)).ToArray();
if (OsInfo.IsNotWindows)
{
folders = subFolders.Select(f => Path.Combine(@"/Test/TV", f)).ToArray();
}
Mocker.GetMock<IConfigService>()
.Setup(s => s.RecycleBin)
.Returns(recycleBinPath);
Mocker.GetMock<IRootFolderRepository>()
.Setup(s => s.Get(It.IsAny<int>()))
.Returns(rootFolder);
Mocker.GetMock<IMovieRepository>()
.Setup(s => s.AllMoviePaths())
.Returns(new Dictionary<int, string>());
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(rootFolder.Path))
.Returns(folders);
var unmappedFolders = Subject.Get(rootFolder.Id, true).UnmappedFolders;
unmappedFolders.Count.Should().Be(3);
}
[Test]
public void should_exclude_recycle_bin()
{
var rootFolder = Builder<RootFolder>.CreateNew()
.With(r => r.Path = @"C:\Test\TV")
.Build();
if (OsInfo.IsNotWindows)
{
rootFolder = Builder<RootFolder>.CreateNew()
.With(r => r.Path = @"/Test/TV")
.Build();
}
var subFolders = new[]
{
"Series1",
"Series2",
"Series3",
"BIN"
};
var folders = subFolders.Select(f => Path.Combine(@"C:\Test\TV", f)).ToArray();
if (OsInfo.IsNotWindows)
{
folders = subFolders.Select(f => Path.Combine(@"/Test/TV", f)).ToArray();
}
var recycleFolder = Path.Combine(OsInfo.IsNotWindows ? @"/Test/TV" : @"C:\Test\TV", "BIN");
Mocker.GetMock<IConfigService>()
.Setup(s => s.RecycleBin)
.Returns(recycleFolder);
Mocker.GetMock<IRootFolderRepository>()
.Setup(s => s.Get(It.IsAny<int>()))
.Returns(rootFolder);
Mocker.GetMock<IMovieRepository>()
.Setup(s => s.AllMoviePaths())
.Returns(new Dictionary<int, string>());
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(rootFolder.Path))
.Returns(folders);
var unmappedFolders = Subject.Get(rootFolder.Id, true).UnmappedFolders;
unmappedFolders.Count.Should().Be(3);
unmappedFolders.Should().NotContain(u => u.Name == "BIN");
}
}
}

View File

@@ -34,7 +34,7 @@ namespace NzbDrone.Core.CustomFormats
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
{
var comparedLanguage = movieInfo != null && Value == Language.Original.Id && movieInfo.ExtraInfo.ContainsKey("OriginalLanguage")
var comparedLanguage = movieInfo != null && Name == "Original" && movieInfo.ExtraInfo.ContainsKey("OriginalLanguage")
? (Language)movieInfo.ExtraInfo["OriginalLanguage"]
: (Language)Value;
return movieInfo?.Languages?.Contains(comparedLanguage) ?? false;

View File

@@ -10,7 +10,7 @@ namespace NzbDrone.Core.CustomFormats
{
public SizeSpecificationValidator()
{
RuleFor(c => c.Min).GreaterThanOrEqualTo(0);
RuleFor(c => c.Min).GreaterThan(0);
RuleFor(c => c.Max).GreaterThan(c => c.Min);
}
}

View File

@@ -1,57 +0,0 @@
using System;
using System.Collections.Generic;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(212)]
public class postgres_update_timestamp_columns_to_with_timezone : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Blocklist").AlterColumn("Date").AsDateTimeOffset().NotNullable();
Alter.Table("Blocklist").AlterColumn("PublishedDate").AsDateTimeOffset().Nullable();
Alter.Table("Collections").AlterColumn("Added").AsDateTimeOffset().Nullable();
Alter.Table("Collections").AlterColumn("LastInfoSync").AsDateTimeOffset().Nullable();
Alter.Table("Commands").AlterColumn("QueuedAt").AsDateTimeOffset().NotNullable();
Alter.Table("Commands").AlterColumn("StartedAt").AsDateTimeOffset().Nullable();
Alter.Table("Commands").AlterColumn("EndedAt").AsDateTimeOffset().Nullable();
Alter.Table("DownloadClientStatus").AlterColumn("InitialFailure").AsDateTimeOffset().Nullable();
Alter.Table("DownloadClientStatus").AlterColumn("MostRecentFailure").AsDateTimeOffset().Nullable();
Alter.Table("DownloadClientStatus").AlterColumn("DisabledTill").AsDateTimeOffset().Nullable();
Alter.Table("DownloadHistory").AlterColumn("Date").AsDateTimeOffset().NotNullable();
Alter.Table("ExtraFiles").AlterColumn("Added").AsDateTimeOffset().NotNullable();
Alter.Table("ExtraFiles").AlterColumn("LastUpdated").AsDateTimeOffset().NotNullable();
Alter.Table("History").AlterColumn("Date").AsDateTimeOffset().NotNullable();
Alter.Table("ImportListStatus").AlterColumn("InitialFailure").AsDateTimeOffset().Nullable();
Alter.Table("ImportListStatus").AlterColumn("MostRecentFailure").AsDateTimeOffset().Nullable();
Alter.Table("ImportListStatus").AlterColumn("DisabledTill").AsDateTimeOffset().Nullable();
Alter.Table("IndexerStatus").AlterColumn("InitialFailure").AsDateTimeOffset().Nullable();
Alter.Table("IndexerStatus").AlterColumn("MostRecentFailure").AsDateTimeOffset().Nullable();
Alter.Table("IndexerStatus").AlterColumn("DisabledTill").AsDateTimeOffset().Nullable();
Alter.Table("IndexerStatus").AlterColumn("CookiesExpirationDate").AsDateTimeOffset().Nullable();
Alter.Table("MetadataFiles").AlterColumn("LastUpdated").AsDateTimeOffset().NotNullable();
Alter.Table("MetadataFiles").AlterColumn("Added").AsDateTimeOffset().Nullable();
Alter.Table("MovieFiles").AlterColumn("DateAdded").AsDateTimeOffset().NotNullable();
Alter.Table("MovieMetadata").AlterColumn("DigitalRelease").AsDateTimeOffset().Nullable();
Alter.Table("MovieMetadata").AlterColumn("InCinemas").AsDateTimeOffset().Nullable();
Alter.Table("MovieMetadata").AlterColumn("LastInfoSync").AsDateTimeOffset().Nullable();
Alter.Table("MovieMetadata").AlterColumn("PhysicalRelease").AsDateTimeOffset().Nullable();
Alter.Table("Movies").AlterColumn("Added").AsDateTimeOffset().Nullable();
Alter.Table("PendingReleases").AlterColumn("Added").AsDateTimeOffset().NotNullable();
Alter.Table("ScheduledTasks").AlterColumn("LastExecution").AsDateTimeOffset().NotNullable();
Alter.Table("ScheduledTasks").AlterColumn("LastStartTime").AsDateTimeOffset().Nullable();
Alter.Table("SubtitleFiles").AlterColumn("Added").AsDateTimeOffset().NotNullable();
Alter.Table("SubtitleFiles").AlterColumn("LastUpdated").AsDateTimeOffset().NotNullable();
Alter.Table("VersionInfo").AlterColumn("AppliedOn").AsDateTimeOffset().Nullable();
}
protected override void LogDbUpgrade()
{
Alter.Table("Logs").AlterColumn("Time").AsDateTimeOffset().NotNullable();
Alter.Table("UpdateHistory").AlterColumn("Date").AsDateTimeOffset().NotNullable();
Alter.Table("VersionInfo").AlterColumn("AppliedOn").AsDateTimeOffset().Nullable();
}
}
}

View File

@@ -305,8 +305,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
details.Add(new XElement("trailer", "plugin://plugin.video.youtube/play/?video_id=" + movie.MovieMetadata.Value.YouTubeTrailerId));
details.Add(new XElement("watched", watched));
if (movieFile.MediaInfo != null)
{
var sceneName = movieFile.GetSceneOrFileName();

View File

@@ -167,7 +167,6 @@ namespace NzbDrone.Core.ImportLists
{
var mappedMovies = reports.Select(m => _movieSearch.MapMovieToTmdbMovie(new MovieMetadata { Title = m.Title, TmdbId = m.TmdbId, ImdbId = m.ImdbId, Year = m.Year }))
.Where(x => x != null)
.DistinctBy(x => x.TmdbId)
.ToList();
_movieMetadataService.UpsertMany(mappedMovies);

View File

@@ -27,13 +27,7 @@ namespace NzbDrone.Core.ImportLists.Trakt.List
{
var link = string.Empty;
// Trakt slug rules:
// - replace all special characters with a dash
// - replaces multiple dashes with a single dash
// - allows underscore as a valid character
// - does not trim underscore from the end
// - allows multiple underscores in a row
var listName = Parser.Parser.ToUrlSlug(Settings.Listname.Trim(), true, "-", "-");
var listName = Parser.Parser.ToUrlSlug(Settings.Listname.Trim());
link += $"users/{Settings.Username.Trim()}/lists/{listName}/items/movies?limit={Settings.Limit}";
var request = new ImportListRequest(_traktProxy.BuildTraktRequest(link, HttpMethod.Get, Settings.AccessToken));

View File

@@ -1,6 +1,4 @@
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
namespace NzbDrone.Core.ImportLists.Trakt.Popular
@@ -11,24 +9,6 @@ namespace NzbDrone.Core.ImportLists.Trakt.Popular
: base()
{
RuleFor(c => c.TraktListType).NotNull();
// Loose validation @TODO
RuleFor(c => c.Rating)
.Matches(@"^\d+\-\d+$", RegexOptions.IgnoreCase)
.When(c => c.Rating.IsNotNullOrWhiteSpace())
.WithMessage("Not a valid rating");
// Any valid certification
RuleFor(c => c.Certification)
.Matches(@"^\bNR\b|\bG\b|\bPG\b|\bPG\-13\b|\bR\b|\bNC\-17\b$", RegexOptions.IgnoreCase)
.When(c => c.Certification.IsNotNullOrWhiteSpace())
.WithMessage("Not a valid cerification");
// Loose validation @TODO
RuleFor(c => c.Years)
.Matches(@"^\d+(\-\d+)?$", RegexOptions.IgnoreCase)
.When(c => c.Years.IsNotNullOrWhiteSpace())
.WithMessage("Not a valid year or range of years");
}
}
@@ -43,17 +23,5 @@ namespace NzbDrone.Core.ImportLists.Trakt.Popular
[FieldDefinition(1, Label = "List Type", Type = FieldType.Select, SelectOptions = typeof(TraktPopularListType), HelpText = "Type of list you're seeking to import from")]
public int TraktListType { get; set; }
[FieldDefinition(2, Label = "Rating", HelpText = "Filter movies by rating range (0-100)")]
public string Rating { get; set; }
[FieldDefinition(3, Label = "Certification", HelpText = "Filter movies by a certification (NR,G,PG,PG-13,R,NC-17), (Comma Separated)")]
public string Certification { get; set; }
[FieldDefinition(4, Label = "Genres", HelpText = "Filter movies by Trakt Genre Slug (Comma Separated) Only for Popular Lists")]
public string Genres { get; set; }
[FieldDefinition(5, Label = "Years", HelpText = "Filter movies by year or year range")]
public string Years { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
@@ -28,6 +29,24 @@ namespace NzbDrone.Core.ImportLists.Trakt
.WithMessage("Must authenticate with Trakt")
.When(c => c.AccessToken.IsNotNullOrWhiteSpace() && c.RefreshToken.IsNotNullOrWhiteSpace());
// Loose validation @TODO
RuleFor(c => c.Rating)
.Matches(@"^\d+\-\d+$", RegexOptions.IgnoreCase)
.When(c => c.Rating.IsNotNullOrWhiteSpace())
.WithMessage("Not a valid rating");
// Any valid certification
RuleFor(c => c.Certification)
.Matches(@"^\bNR\b|\bG\b|\bPG\b|\bPG\-13\b|\bR\b|\bNC\-17\b$", RegexOptions.IgnoreCase)
.When(c => c.Certification.IsNotNullOrWhiteSpace())
.WithMessage("Not a valid cerification");
// Loose validation @TODO
RuleFor(c => c.Years)
.Matches(@"^\d+(\-\d+)?$", RegexOptions.IgnoreCase)
.When(c => c.Years.IsNotNullOrWhiteSpace())
.WithMessage("Not a valid year or range of years");
// Limit not smaller than 1 and not larger than 100
RuleFor(c => c.Limit)
.GreaterThan(0)
@@ -43,6 +62,10 @@ namespace NzbDrone.Core.ImportLists.Trakt
public TraktSettingsBase()
{
SignIn = "startOAuth";
Rating = "0-100";
Certification = "NR,G,PG,PG-13,R,NC-17";
Genres = "";
Years = "";
Limit = 100;
}
@@ -61,6 +84,18 @@ namespace NzbDrone.Core.ImportLists.Trakt
[FieldDefinition(0, Label = "Auth User", Type = FieldType.Textbox, Hidden = HiddenType.Hidden)]
public string AuthUser { get; set; }
[FieldDefinition(1, Label = "Rating", HelpText = "Filter movies by rating range (0-100)")]
public string Rating { get; set; }
[FieldDefinition(2, Label = "Certification", HelpText = "Filter movies by a certification (NR,G,PG,PG-13,R,NC-17), (Comma Separated)")]
public string Certification { get; set; }
[FieldDefinition(3, Label = "Genres", HelpText = "Filter movies by Trakt Genre Slug (Comma Separated) Only for Popular Lists")]
public string Genres { get; set; }
[FieldDefinition(4, Label = "Years", HelpText = "Filter movies by year or year range")]
public string Years { get; set; }
[FieldDefinition(5, Label = "Limit", HelpText = "Limit the number of movies to get")]
public int Limit { get; set; }

View File

@@ -42,15 +42,14 @@ namespace NzbDrone.Core.IndexerSearch
foreach (var movieId in message.MovieIds)
{
var movie = _movieService.GetMovie(movieId);
var userInvokedSearch = message.Trigger == CommandTrigger.Manual;
if (!movie.Monitored && !userInvokedSearch)
if (!movie.Monitored && message.Trigger != CommandTrigger.Manual)
{
_logger.Debug("Movie {0} is not monitored, skipping search", movie.Title);
continue;
}
var decisions = _releaseSearchService.MovieSearch(movieId, userInvokedSearch, false);
var decisions = _releaseSearchService.MovieSearch(movieId, false, false);
downloadedCount += _processDownloadDecisions.ProcessDecisions(decisions).Grabbed.Count;
}

View File

@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Indexers
{
if (InfoHashElementName.IsNotNullOrWhiteSpace())
{
return item.FindDecendants(InfoHashElementName).FirstOrDefault()?.Value;
return item.FindDecendants(InfoHashElementName).FirstOrDefault().Value;
}
var magnetUrl = GetMagnetUrl(item);
@@ -96,7 +96,7 @@ namespace NzbDrone.Core.Indexers
{
if (MagnetElementName.IsNotNullOrWhiteSpace())
{
var magnetURL = item.FindDecendants(MagnetElementName).FirstOrDefault()?.Value;
var magnetURL = item.FindDecendants(MagnetElementName).FirstOrDefault().Value;
if (magnetURL.IsNotNullOrWhiteSpace() && magnetURL.StartsWith("magnet:"))
{
return magnetURL;

View File

@@ -105,7 +105,6 @@ namespace NzbDrone.Core.Languages
public static Language Ukrainian => new Language(32, "Ukrainian");
public static Language Persian => new Language(33, "Persian");
public static Language Bengali => new Language(34, "Bengali");
public static Language Slovak => new Language(35, "Slovak");
public static Language Any => new Language(-1, "Any");
public static Language Original => new Language(-2, "Original");
@@ -150,7 +149,6 @@ namespace NzbDrone.Core.Languages
Ukrainian,
Persian,
Bengali,
Slovak,
Any,
Original
};

File diff suppressed because it is too large Load Diff

View File

@@ -1119,6 +1119,5 @@
"ChooseImportMode": "Elegir Modo de Importación",
"CollectionOptions": "Opciones de la Colección",
"CollectionShowDetailsHelpText": "Mostrar el estado y propiedades de la colección",
"CollectionShowOverviewsHelpText": "Mostrar resumenes de la colección",
"CollectionShowPostersHelpText": "Mostrar póster de artículos de colección"
"CollectionShowOverviewsHelpText": "Mostrar resumenes de la colección"
}

View File

@@ -1142,6 +1142,5 @@
"CollectionOptions": "Kokoelmien valinnat",
"CollectionShowDetailsHelpText": "Näytä kokoelmien tila ja ominaisuudet",
"CollectionShowPostersHelpText": "Näytä kokoelmien julisteet",
"RottenTomatoesRating": "Tomaattiarvio",
"TotalMovies": "Elokuvia yhteensä"
"RottenTomatoesRating": "Tomaattiarvio"
}

View File

@@ -106,7 +106,7 @@
"RemotePathMappings": "Mappages de chemins distants",
"ReleaseBranchCheckOfficialBranchMessage": "La branche {0} n'est pas une branche de version Radarr valide, vous ne recevrez pas de mises à jour",
"RefreshAndScan": "Actualiser et analyser",
"Refresh": "Actualiser",
"Refresh": "Rafraîchir",
"Ratings": "Évaluations",
"Queue": "File d'attente",
"QualitySettingsSummary": "Tailles qualité et dénomination",
@@ -1114,7 +1114,7 @@
"SetReleaseGroup": "Régler le groupe de publication",
"RefreshMonitoredIntervalHelpText": "Intervalle en minutes entre chaque vérification des téléchargements, minimum 1 minute",
"AllCollectionsHiddenDueToFilter": "Tous les films sont masqués en raison du filtre appliqué.",
"Collections": "Collections",
"Collections": "Collection",
"MonitorMovies": "Surveiller le film",
"NoCollections": "Aucun film trouvé, pour commencer, vous voudrez ajouter un nouveau film ou importer des films existants.",
"RssSyncHelpText": "Intervalle en minutes. Mettre à zéro pour désactiver (cela arrêtera tous les téléchargements automatiques)",
@@ -1122,20 +1122,5 @@
"ChooseImportMode": "Mode d'importation",
"CollectionOptions": "Options de collection",
"CollectionShowDetailsHelpText": "Afficher l'état et les propriétés de la collection",
"CollectionShowOverviewsHelpText": "Afficher les aperçus des collections",
"OnMovieAddedHelpText": "À l'ajout d'un film",
"MovieAndCollection": "Film et collection",
"ShowOverview": "Afficher l'aperçu",
"MovieCollectionMissingRoot": "Dossier racine manquant pour la collection de films : {0}",
"OnMovieAdded": "À l'ajout d'un film",
"MonitorCollection": "Surveiller la collection",
"MonitoredCollectionHelpText": "Surveiller pour ajouter automatiquement les films de cette collection à la bibliothèque",
"MovieCollectionMultipleMissingRoots": "Plusieurs dossiers racine manquent pour les collections de films: {0}",
"MovieOnly": "Film seulement",
"RefreshCollections": "Actualiser les collections",
"SearchOnAddCollectionHelpText": "Rechercher des films dans cette collection lorsqu'ils sont ajoutés à Radarr",
"UnableToLoadCollections": "Impossible de charger les collections",
"RottenTomatoesRating": "Classement Rotten Tomatoes",
"ShowCollectionDetails": "Afficher l'état de la collection",
"EditCollection": "Modifier la collection"
"CollectionShowOverviewsHelpText": "Afficher les aperçus des collections"
}

View File

@@ -21,7 +21,7 @@
"AddExclusion": "Kivétel hozzáadása",
"Activity": "Aktivitás",
"Error": "Hiba",
"Ended": "Vége lett",
"Ended": "Befejezve",
"EnableCompletedDownloadHandlingHelpText": "A befejezett letöltések automatikus importálása a letöltési kliensből",
"EnableColorImpairedModeHelpText": "Megváltoztatott színek, hogy a színvak felhasználók jobban meg tudják különböztetni a színkódolt információkat",
"EnableAutomaticSearchHelpTextWarning": "Interaktív keresés esetén is felhasználható",
@@ -434,7 +434,7 @@
"RadarrSupportsAnyIndexer": "A Radarr minden indexert támogat, amely a Newznab szabványt használja, valamint az alább felsorolt egyéb indexereket.",
"RadarrSupportsAnyDownloadClient": "A Radarr számos népszerű torrent és usenet letöltési ügyfelet támogat.",
"QuickImport": "Automatikus Áthelyezés",
"Queued": "Sorba helyezve",
"Queued": "Sorban",
"Queue": "Várakozási sor",
"QualitySettingsSummary": "Minőségi méretek és elnevezés",
"QualitySettings": "Minőségi beállítások",
@@ -616,7 +616,7 @@
"Level": "Szint",
"LaunchBrowserHelpText": " Nyisson meg egy böngészőt, és az alkalmazás indításakor lépjen a Radarr kezdőlapjára.",
"LastWriteTime": "Utolsó írási idő",
"LastDuration": "Utolsó időtartam",
"LastDuration": "Utolsó Hossza",
"Languages": "Nyelvek",
"LanguageHelpText": "Nyelv a Releasekhez",
"Language": "Nyelv",
@@ -896,7 +896,7 @@
"HomePage": "Kezdőlap",
"LogOnly": "Csak naplózás",
"LastUsed": "Utoljára használt",
"LastExecution": "Utol végrehajtás",
"LastExecution": "Utoljára végrehajtott",
"Large": "Óriási",
"KeepAndUnmonitorMovie": "Megtartás és megfigyelés kikapcsolása a filmnél",
"InvalidFormat": "Érvénytelen Formátum",
@@ -992,7 +992,7 @@
"NoLinks": "Nincsenek Linkek",
"NoEventsFound": "Nem található esemény",
"NoAltTitle": "Nincs alternatív cím.",
"NextExecution": "Következő végrehajtás",
"NextExecution": "Következő futtatás",
"Negated": "Megtagadva",
"Negate": "Megtagadás",
"MultiLanguage": "Többnyelvű",
@@ -1105,7 +1105,7 @@
"Never": "Soha",
"Rating": "Értékelés",
"SetReleaseGroup": "Kiadási csoport beállítása",
"Started": "Elkezdődött",
"Started": "Elindult",
"Waiting": "Várakozás",
"OnApplicationUpdateHelpText": "Alkalmazásfrissítésről",
"SizeLimit": "Méretkorlát",
@@ -1142,6 +1142,5 @@
"OnMovieAddedHelpText": "Film hozzáadásakor",
"ShowPosters": "Poszterek megjelenítése",
"InstanceNameHelpText": "Példánynév a böngésző lapon és a syslog alkalmazás neve",
"RottenTomatoesRating": "Tomato Értékelés",
"TotalMovies": "Összes film"
"RottenTomatoesRating": "Tomato Értékelés"
}

View File

@@ -254,6 +254,5 @@
"Language": "språk",
"List": "Liste",
"New": "Ny",
"RemotePathMappings": "Ekstern portmapping",
"Languages": "språk"
"RemotePathMappings": "Ekstern portmapping"
}

View File

@@ -1062,7 +1062,7 @@
"Collections": "Kolekcje",
"RssSyncHelpText": "Odstęp w minutach. Ustaw na zero, aby wyłączyć (zatrzyma to wszystkie automatyczne przechwytywanie zwolnień)",
"NoCollections": "Nie znaleziono żadnych filmów. Aby rozpocząć, musisz dodać nowy film lub zaimportować istniejące",
"MonitorMovies": "Monitoruj filmy",
"MonitorMovies": "Monitoruj film",
"ClickToChangeReleaseGroup": "Kliknij, by zmienić grupę wydającą",
"RemotePathMappingCheckDownloadPermissions": "Radarr widzi film {0}, lecz nie ma do niego dostępu. Najprawdopodobniej to wynik błędu w uprawnieniach dostępu.",
"NotificationTriggersHelpText": "Wybierz zdarzenia, które mają uruchamiać to powiadomienie",
@@ -1078,7 +1078,7 @@
"ManualImportSetReleaseGroup": "Import ręczny - podaj nazwę grupy",
"Never": "Nigdy",
"RemotePathMappingCheckFilesWrongOSPath": "Zdalny klient pobierania {0} zgłosił pliki w {1}, lecz nie jest to poprawna ścieżka {2}. Zmień ustawienia zdalnego mapowania ścieżek i klienta pobierania.",
"RemotePathMappingCheckGenericPermissions": "Klient pobierania {0} umieszcza pobrane pliki w {1}, ale Radarr nie widzi tego folderu. Być może należy zmienić uprawnienia dostępu do folderu/ścieżkę dostępu.",
"RemotePathMappingCheckGenericPermissions": "Klient pobierania {0} umieszcza pobrane pliki w {1}, lecz Radarr nie widzi tego folderu. Być może należy zmienić uprawnienia dostępu do folderu.",
"RemoveFailed": "Usuń nieudane",
"RemoveDownloadsAlert": "Ustawienia usuwania zostały przeniesione do ustawień poszczególnych klientów pobierania powyżej.",
"ShowCollectionDetails": "Pokaż stan kolekcji",
@@ -1141,7 +1141,5 @@
"CollectionShowPostersHelpText": "Pokaż plakaty elementów kolekcji",
"CollectionOptions": "Opcje Kolekcji",
"CollectionShowDetailsHelpText": "Pokaż status i właściwości kolekcji",
"CollectionShowOverviewsHelpText": "Pokaż przegląd kolekcji",
"TotalMovies": "Filmów całkowicie",
"RottenTomatoesRating": "Ocena Tomato"
"CollectionShowOverviewsHelpText": "Pokaż przegląd kolekcji"
}

View File

@@ -1142,6 +1142,5 @@
"CollectionShowDetailsHelpText": "Mostrar estado e propriedades da coleção",
"CollectionShowOverviewsHelpText": "Mostrar visão geral da coleção",
"CollectionShowPostersHelpText": "Mostrar pôsteres de itens da coleção",
"RottenTomatoesRating": "Avaliação Tomato",
"TotalMovies": "Total de Filmes"
"RottenTomatoesRating": "Avaliação Tomato"
}

View File

@@ -637,7 +637,7 @@
"InstallLatest": "安装最新版",
"IndexerStatusCheckSingleClientMessage": "搜刮器因错误不可用:{0}",
"IndexerStatusCheckAllClientMessage": "所有搜刮器都因错误不可用",
"IndexerSearchCheckNoInteractiveMessage": "没有任何索引器开启了手动搜索Radarr 不会提供任何手动搜索结果",
"IndexerSearchCheckNoInteractiveMessage": "没有任何索引器开启了手动搜索Radarr 不会提供任何手动搜索结果",
"IndexerRssHealthCheckNoIndexers": "没有任何索引器开启了RSS同步Radarr不会自动抓取新发布的影片",
"IndexerLongTermStatusCheckSingleClientMessage": "由于故障6小时下列索引器都已不可用{0}",
"IndexerLongTermStatusCheckAllClientMessage": "由于故障超过6小时所有索引器均不可用",
@@ -740,7 +740,7 @@
"UnableToAddANewNotificationPleaseTryAgain": "无法添加新通知,请稍后重试。",
"URLBase": "基本URL",
"RemovedMovieCheckMultipleMessage": "电影“{0}”已从TMDb移除",
"SkipFreeSpaceCheckWhenImportingHelpText": "当 Radarr 无法从movie根目录检测到空间时使用",
"SkipFreeSpaceCheckWhenImportingHelpText": "当 Radarr 无法从您的电影根文件夹中检测到空闲空间时使用",
"UnableToAddANewQualityProfilePleaseTryAgain": "无法添加新影片质量配置,请稍后重试。",
"ThisCannotBeCancelled": "在不禁用所有索引器的情况下,一旦启动就无法取消。",
"SearchCutoffUnmet": "搜索未满足终止条件的",
@@ -1135,12 +1135,5 @@
"NoCollections": "没有发现集合,点击添加新的电影或者导入已经存在的电影",
"InstanceNameHelpText": "选项卡及日志应用名称",
"ScrollMovies": "滚动电影",
"CollectionOptions": "集选项Collection Options",
"CollectionShowDetailsHelpText": "显示集合collection的状态和属性",
"CollectionShowOverviewsHelpText": "显示集合collection的概述",
"CollectionShowPostersHelpText": "显示集合项目海报",
"RottenTomatoesRating": "烂番茄指数",
"ShowPosters": "显示海报",
"OnMovieAdded": "电影添加时",
"OnMovieAddedHelpText": "电影添加时"
"CollectionOptions": "Collection Options"
}

View File

@@ -1,14 +1,7 @@
{
"About": "關於",
"Add": "新增",
"Add": "添加",
"AcceptConfirmationModal": "接受確認模式",
"Actions": "執行",
"Activity": "‎活動‎",
"AddIndexer": "新增索引",
"AddingTag": "新增標籤",
"AddDownloadClient": "新增下載器",
"Added": "以新增",
"Age": "年齡",
"All": "全部",
"Analytics": "分析"
"Actions": "‎行動‎",
"Activity": "‎活動‎"
}

View File

@@ -5,7 +5,6 @@ using System.Linq;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
@@ -261,20 +260,6 @@ namespace NzbDrone.Core.MediaFiles
};
}
var extension = Path.GetExtension(fileInfo.Name);
if (extension.IsNullOrWhiteSpace() || !MediaFileExtensions.Extensions.Contains(extension))
{
_logger.Debug("[{0}] has an unsupported extension: '{1}'", fileInfo.FullName, extension);
return new List<ImportResult>
{
new ImportResult(new ImportDecision(new LocalMovie { Path = fileInfo.FullName },
new Rejection($"Invalid video file, unsupported extension: '{extension}'")),
$"Invalid video file, unsupported extension: '{extension}'")
};
}
if (downloadClientItem == null)
{
if (_diskProvider.IsFileLocked(fileInfo.FullName))

View File

@@ -344,16 +344,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
yearStr = $" {movie.Year}";
}
var newMovieObject = SearchForNewMovie(movie.Title + yearStr).FirstOrDefault();
if (newMovieObject == null)
{
newMovie = null;
}
else
{
newMovie = newMovieObject.MovieMetadata;
}
newMovie = SearchForNewMovie(movie.Title + yearStr).FirstOrDefault()?.MovieMetadata ?? null;
}
if (newMovie == null)

View File

@@ -56,7 +56,7 @@ namespace NzbDrone.Core.Movies
_diskProvider.CreateFolder(new DirectoryInfo(destinationPath).Parent.FullName);
_diskTransferService.TransferFolder(sourcePath, destinationPath, TransferMode.Move);
_logger.ProgressInfo("{0} moved successfully to {1}", movie.Title, destinationPath);
_logger.ProgressInfo("{0} moved successfully to {1}", movie.Title, movie.Path);
_eventAggregator.PublishEvent(new MovieMovedEvent(movie, sourcePath, destinationPath));
}

View File

@@ -119,18 +119,10 @@ namespace NzbDrone.Core.Movies
return FindByTitle(new List<string> { title }, year, otherTitles, candidates);
}
public Movie FindByTitle(List<string> titles, int? year, List<string> otherTitles, List<Movie> candidates)
public Movie FindByTitle(List<string> cleanTitles, int? year, List<string> otherTitles, List<Movie> candidates)
{
var cleanTitles = titles.Select(t => t.CleanMovieTitle().ToLowerInvariant());
var result = candidates.Where(x => cleanTitles.Contains(x.MovieMetadata.Value.CleanTitle)).FirstWithYear(year);
if (result == null)
{
result =
candidates.Where(movie => cleanTitles.Contains(movie.MovieMetadata.Value.CleanOriginalTitle)).FirstWithYear(year);
}
if (result == null)
{
result =

View File

@@ -98,14 +98,6 @@ namespace NzbDrone.Core.Notifications.Discord
discordField.Name = "Links";
discordField.Value = GetLinksString(message.Movie);
break;
case DiscordGrabFieldType.CustomFormats:
discordField.Name = "Custom Formats";
discordField.Value = string.Join("|", message.RemoteMovie.CustomFormats);
break;
case DiscordGrabFieldType.CustomFormatScore:
discordField.Name = "Custom Format Score";
discordField.Value = message.RemoteMovie.CustomFormatScore.ToString();
break;
}
if (discordField.Name.IsNotNullOrWhiteSpace() && discordField.Value.IsNotNullOrWhiteSpace())

View File

@@ -11,9 +11,7 @@ namespace NzbDrone.Core.Notifications.Discord
Links,
Release,
Poster,
Fanart,
CustomFormats,
CustomFormatScore
Fanart
}
public enum DiscordImportFieldType

View File

@@ -0,0 +1,8 @@
namespace NzbDrone.Core.Notifications.Notifiarr
{
public enum NotifiarrEnvironment
{
Live,
Development
}
}

View File

@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Notifications.Notifiarr
{
try
{
var url = "https://notifiarr.com";
var url = settings.Environment == (int)NotifiarrEnvironment.Development ? "https://dev.notifiarr.com" : "https://notifiarr.com";
var requestBuilder = new HttpRequestBuilder(url + "/api/v1/notification/radarr/" + settings.APIKey).Post();
requestBuilder.AddFormParameter("instanceName", settings.InstanceName).Build();

View File

@@ -21,6 +21,8 @@ namespace NzbDrone.Core.Notifications.Notifiarr
public string APIKey { get; set; }
[FieldDefinition(1, Label = "Instance Name", Advanced = true, HelpText = "Unique name for this instance", HelpLink = "https://notifiarr.com")]
public string InstanceName { get; set; }
[FieldDefinition(2, Label = "Environment", Advanced = true, Type = FieldType.Select, SelectOptions = typeof(NotifiarrEnvironment), HelpText = "Live unless told otherwise", HelpLink = "https://notifiarr.com")]
public int Environment { get; set; }
public NzbDroneValidationResult Validate()
{

View File

@@ -1,66 +0,0 @@
using System.Collections.Generic;
using FluentValidation.Results;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Movies;
namespace NzbDrone.Core.Notifications.Ntfy
{
public class Ntfy : NotificationBase<NtfySettings>
{
private readonly INtfyProxy _proxy;
public Ntfy(INtfyProxy proxy)
{
_proxy = proxy;
}
public override string Name => "ntfy.sh";
public override string Link => "https://ntfy.sh/";
public override void OnGrab(GrabMessage grabMessage)
{
_proxy.SendNotification(MOVIE_GRABBED_TITLE_BRANDED, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
_proxy.SendNotification(MOVIE_DOWNLOADED_TITLE_BRANDED, message.Message, Settings);
}
public override void OnMovieAdded(Movie movie)
{
_proxy.SendNotification(MOVIE_ADDED_TITLE_BRANDED, $"{movie.Title} added to library", Settings);
}
public override void OnMovieFileDelete(MovieFileDeleteMessage deleteMessage)
{
_proxy.SendNotification(MOVIE_FILE_DELETED_TITLE, deleteMessage.Message, Settings);
}
public override void OnMovieDelete(MovieDeleteMessage deleteMessage)
{
_proxy.SendNotification(MOVIE_DELETED_TITLE, deleteMessage.Message, Settings);
}
public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
{
_proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message, Settings);
}
public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage)
{
_proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_proxy.Test(Settings));
return new ValidationResult(failures);
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Notifications.Ntfy
{
public class NtfyException : NzbDroneException
{
public NtfyException(string message)
: base(message)
{
}
public NtfyException(string message, Exception innerException, params object[] args)
: base(message, innerException, args)
{
}
}
}

View File

@@ -1,11 +0,0 @@
namespace NzbDrone.Core.Notifications.Ntfy
{
public enum NtfyPriority
{
Min = 1,
Low = 2,
Default = 3,
High = 4,
Max = 5
}
}

View File

@@ -1,138 +0,0 @@
using System;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
namespace NzbDrone.Core.Notifications.Ntfy
{
public interface INtfyProxy
{
void SendNotification(string title, string message, NtfySettings settings);
ValidationFailure Test(NtfySettings settings);
}
public class NtfyProxy : INtfyProxy
{
private const string DEFAULT_PUSH_URL = "https://ntfy.sh";
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
public NtfyProxy(IHttpClient httpClient, Logger logger)
{
_httpClient = httpClient;
_logger = logger;
}
public void SendNotification(string title, string message, NtfySettings settings)
{
var error = false;
var serverUrl = settings.ServerUrl.IsNullOrWhiteSpace() ? NtfyProxy.DEFAULT_PUSH_URL : settings.ServerUrl;
foreach (var topic in settings.Topics)
{
var request = BuildTopicRequest(serverUrl, topic);
try
{
SendNotification(title, message, request, settings);
}
catch (NtfyException ex)
{
_logger.Error(ex, "Unable to send test message to {0}", topic);
error = true;
}
}
if (error)
{
throw new NtfyException("Unable to send Ntfy notifications to all topics");
}
}
private HttpRequestBuilder BuildTopicRequest(string serverUrl, string topic)
{
var trimServerUrl = serverUrl.TrimEnd('/');
var requestBuilder = new HttpRequestBuilder($"{trimServerUrl}/{topic}").Post();
return requestBuilder;
}
public ValidationFailure Test(NtfySettings settings)
{
try
{
const string title = "Radarr - Test Notification";
const string body = "This is a test message from Radarr";
SendNotification(title, body, settings);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized || ex.Response.StatusCode == HttpStatusCode.Forbidden)
{
_logger.Error(ex, "Authorization is required");
return new ValidationFailure("UserName", "Authorization is required");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("ServerUrl", "Unable to send test message");
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
}
return null;
}
private void SendNotification(string title, string message, HttpRequestBuilder requestBuilder, NtfySettings settings)
{
try
{
requestBuilder.Headers.Add("X-Title", title);
requestBuilder.Headers.Add("X-Message", message);
requestBuilder.Headers.Add("X-Priority", settings.Priority.ToString());
if (settings.Tags.Any())
{
requestBuilder.Headers.Add("X-Tags", settings.Tags.Join(","));
}
if (!settings.ClickUrl.IsNullOrWhiteSpace())
{
requestBuilder.Headers.Add("X-Click", settings.ClickUrl);
}
var request = requestBuilder.Build();
if (!settings.UserName.IsNullOrWhiteSpace() && !settings.Password.IsNullOrWhiteSpace())
{
request.Credentials = new BasicNetworkCredential(settings.UserName, settings.Password);
}
_httpClient.Execute(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized || ex.Response.StatusCode == HttpStatusCode.Forbidden)
{
_logger.Error(ex, "Authorization is required");
throw;
}
throw new NtfyException("Unable to send text message: {0}", ex, ex.Message);
}
}
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Ntfy
{
public class NtfySettingsValidator : AbstractValidator<NtfySettings>
{
public NtfySettingsValidator()
{
RuleFor(c => c.Topics).NotEmpty();
RuleFor(c => c.Priority).InclusiveBetween(1, 5);
RuleFor(c => c.ServerUrl).IsValidUrl().When(c => !c.ServerUrl.IsNullOrWhiteSpace());
RuleFor(c => c.ClickUrl).IsValidUrl().When(c => !c.ClickUrl.IsNullOrWhiteSpace());
RuleFor(c => c.UserName).NotEmpty().When(c => !c.Password.IsNullOrWhiteSpace());
RuleFor(c => c.Password).NotEmpty().When(c => !c.UserName.IsNullOrWhiteSpace());
RuleForEach(c => c.Topics).NotEmpty().Matches("[a-zA-Z0-9_-]+").Must(c => !InvalidTopics.Contains(c)).WithMessage("Invalid topic");
}
private static List<string> InvalidTopics => new List<string> { "announcements", "app", "docs", "settings", "stats", "mytopic-rw", "mytopic-ro", "mytopic-wo" };
}
public class NtfySettings : IProviderConfig
{
private static readonly NtfySettingsValidator Validator = new NtfySettingsValidator();
public NtfySettings()
{
Topics = Array.Empty<string>();
Priority = 3;
}
[FieldDefinition(0, Label = "Server Url", Type = FieldType.Url, HelpLink = "https://ntfy.sh/docs/install/", HelpText = "Leave blank to use public server (https://ntfy.sh)", Placeholder = "https://ntfy.sh")]
public string ServerUrl { get; set; }
[FieldDefinition(1, Label = "User Name", HelpText = "Optional Authorization", Privacy = PrivacyLevel.UserName)]
public string UserName { get; set; }
[FieldDefinition(2, Label = "Password", Type = FieldType.Password, HelpText = "Optional Password", Privacy = PrivacyLevel.Password)]
public string Password { get; set; }
[FieldDefinition(3, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(NtfyPriority))]
public int Priority { get; set; }
[FieldDefinition(4, Label = "Topics", HelpText = "List of Topics to send notifications to", Type = FieldType.Tag, Placeholder = "Topic1234,Topic4321")]
public IEnumerable<string> Topics { get; set; }
[FieldDefinition(5, Label = "Ntfy Tags and Emojis", Type = FieldType.Tag, HelpText = "Optional list of tags or emojis to use", Placeholder = "warning,skull", HelpLink = "https://ntfy.sh/docs/emojis/")]
public IEnumerable<string> Tags { get; set; }
[FieldDefinition(6, Label = "Click Url", Type = FieldType.Url, HelpText = "Optional link when user clicks notification", Placeholder = "https://myserver.example.com/radarr")]
public string ClickUrl { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

View File

@@ -38,9 +38,20 @@ namespace NzbDrone.Core.Organizer
private readonly ICustomFormatService _formatService;
private readonly Logger _logger;
private static readonly Regex TitleRegex = new Regex(@"(?<tag>\{(?:imdb-|edition-))?\{(?<prefix>[- ._\[(]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9|]+))?(?<suffix>[-} ._)\]]*)\}",
private static readonly Regex TitleRegex = new Regex(@"\{(?<prefix>[- ._\[(]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9|]+))?(?<suffix>[- ._)\]]*)\}",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private static readonly Regex TagsRegex = new Regex(@"(?<tags>\{tags(?:\:0+)?})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex SeasonEpisodePatternRegex = new Regex(@"(?<separator>(?<=})[- ._]+?)?(?<seasonEpisode>s?{season(?:\:0+)?}(?<episodeSeparator>[- ._]?[ex])(?<episode>{episode(?:\:0+)?}))(?<separator>[- ._]+?(?={))?",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex AbsoluteEpisodePatternRegex = new Regex(@"(?<separator>(?<=})[- ._]+?)?(?<absolute>{absolute(?:\:0+)?})(?<separator>[- ._]+?(?={))?",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex AirDateRegex = new Regex(@"\{Air(\s|\W|_)Date\}", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean|Original)?(Title|Filename)(The)?)(?::(?<customFormat>[a-z0-9|]+))?\})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -50,6 +61,11 @@ namespace NzbDrone.Core.Organizer
private static readonly Regex ScenifyRemoveChars = new Regex(@"(?<=\s)(,|<|>|\/|\\|;|:|'|""|\||`|~|!|\?|@|$|%|^|\*|-|_|=){1}(?=\s)|('|:|\?|,)(?=(?:(?:s|m)\s)|\s|$)|(\(|\)|\[|\]|\{|\})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ScenifyReplaceChars = new Regex(@"[\/]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
//TODO: Support Written numbers (One, Two, etc) and Roman Numerals (I, II, III etc)
private static readonly Regex MultiPartCleanupRegex = new Regex(@"(?:\(\d+\)|(Part|Pt\.?)\s?\d+)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly char[] EpisodeTitleTrimCharacters = new[] { ' ', '.', '?' };
private static readonly Regex TitlePrefixRegex = new Regex(@"^(The|An|A) (.*?)((?: *\([^)]+\))*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ReservedDeviceNamesRegex = new Regex(@"^(?:aux|com[1-9]|con|lpt[1-9]|nul|prn)\.", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -117,7 +133,7 @@ namespace NzbDrone.Core.Organizer
AddQualityTokens(tokenHandlers, movie, movieFile);
AddMediaInfoTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile);
AddEditionTagsTokens(tokenHandlers, movieFile);
AddTagsTokens(tokenHandlers, movieFile);
AddCustomFormats(tokenHandlers, movie, movieFile, customFormats);
var splitPatterns = pattern.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
@@ -177,7 +193,7 @@ namespace NzbDrone.Core.Organizer
AddQualityTokens(tokenHandlers, movie, movieFile);
AddMediaInfoTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile);
AddEditionTagsTokens(tokenHandlers, movieFile);
AddTagsTokens(tokenHandlers, movieFile);
}
else
{
@@ -281,7 +297,7 @@ namespace NzbDrone.Core.Organizer
return movie.Title;
}
private void AddEditionTagsTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile)
private void AddTagsTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile)
{
if (movieFile.Edition.IsNotNullOrWhiteSpace())
{
@@ -481,7 +497,6 @@ namespace NzbDrone.Core.Organizer
var tokenMatch = new TokenMatch
{
RegexMatch = match,
Tag = match.Groups["tag"].Value,
Prefix = match.Groups["prefix"].Value,
Separator = match.Groups["separator"].Value,
Suffix = match.Groups["suffix"].Value,
@@ -516,7 +531,7 @@ namespace NzbDrone.Core.Organizer
if (!replacementText.IsNullOrWhiteSpace())
{
replacementText = tokenMatch.Tag + tokenMatch.Prefix + replacementText + tokenMatch.Suffix;
replacementText = tokenMatch.Prefix + replacementText + tokenMatch.Suffix;
}
return replacementText;
@@ -583,7 +598,6 @@ namespace NzbDrone.Core.Organizer
internal sealed class TokenMatch
{
public Match RegexMatch { get; set; }
public string Tag { get; set; }
public string Prefix { get; set; }
public string Separator { get; set; }
public string Suffix { get; set; }

View File

@@ -42,8 +42,7 @@ namespace NzbDrone.Core.Parser
new IsoLanguage("uk", "", "ukr", "Ukrainian", Language.Ukrainian),
new IsoLanguage("fa", "", "fas", "Persian", Language.Persian),
new IsoLanguage("be", "", "ben", "Bengali", Language.Bengali),
new IsoLanguage("lt", "", "lit", "Lithuanian", Language.Lithuanian),
new IsoLanguage("sk", "", "slk", "Slovak", Language.Slovak)
new IsoLanguage("lt", "", "lit", "Lithuanian", Language.Lithuanian)
};
public static IsoLanguage Find(string isoCode)

View File

@@ -32,8 +32,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex CaseSensitiveLanguageRegex = new Regex(@"(?:(?i)(?<!SUB[\W|_|^]))(?:(?<lithuanian>\bLT\b)|
(?<czech>\bCZ\b)|
(?<polish>\bPL\b)|
(?<bulgarian>\bBG\b))(?:(?i)(?![\W|_|^]SUB))|
(?<slovak>\bSK\b)",
(?<bulgarian>\bBG\b))(?:(?i)(?![\W|_|^]SUB))",
RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex SubtitleLanguageRegex = new Regex(".+?[-_. ](?<iso_code>[a-z]{2,3})(?:[-_. ]forced)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -183,11 +182,6 @@ namespace NzbDrone.Core.Parser
languages.Add(Language.Bengali);
}
if (lowerTitle.Contains("slovak"))
{
languages.Add(Language.Slovak);
}
// Case sensitive
var caseSensitiveMatch = CaseSensitiveLanguageRegex.Match(title);
@@ -211,11 +205,6 @@ namespace NzbDrone.Core.Parser
languages.Add(Language.Bulgarian);
}
if (caseSensitiveMatch.Groups["slovak"].Captures.Cast<Capture>().Any())
{
languages.Add(Language.Slovak);
}
var matches = LanguageRegex.Matches(title);
foreach (Match match in matches)

View File

@@ -147,11 +147,11 @@ namespace NzbDrone.Core.Parser
//Handle Exception Release Groups that don't follow -RlsGrp; Manual List
//groups whose releases end with RlsGroup) or RlsGroup]
private static readonly Regex ExceptionReleaseGroupRegex = new Regex(@"(?<releasegroup>(Joy|YIFY|YTS.MX|YTS.LT|FreetheFish|afm72|Anna|Bandi|Ghost|Kappa|MONOLITH|Qman|RZeroX|SAMPA|Silence|theincognito|t3nzin|Vyndros|HDO|DusIctv|DHD|SEV|CtrlHD|-ZR-|ADC|XZVN|RH|Kametsu|r00t|HONE)(?=\]|\)))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex ExceptionReleaseGroupRegex = new Regex(@"(?<releasegroup>(Tigole|Joy|YIFY|YTS.MX|YTS.LT|FreetheFish|afm72|Anna|Bandi|Ghost|Kappa|MONOLITH|Qman|RZeroX|SAMPA|Silence|theincognito|t3nzin|Vyndros|HDO|DusIctv|DHD|SEV|CtrlHD|-ZR-|ADC|XZVN|RH|Kametsu|r00t)(?=\]|\)))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
//Handle Exception Release Groups that don't follow -RlsGrp; Manual List
// name only...BE VERY CAREFUL WITH THIS, HIGH CHANCE OF FALSE POSITIVES
private static readonly Regex ExceptionReleaseGroupRegexExact = new Regex(@"(?<releasegroup>KRaLiMaRKo|E\.N\.D|D\-Z0N3|Koten_Gars|BluDragon|ZØNEHD|Tigole)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex ExceptionReleaseGroupRegexExact = new Regex(@"(?<releasegroup>KRaLiMaRKo|E\.N\.D|D\-Z0N3|Koten_Gars|BluDragon)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex WordDelimiterRegex = new Regex(@"(\s|\.|,|_|-|=|'|\|)+", RegexOptions.Compiled);
private static readonly Regex SpecialCharRegex = new Regex(@"(\&|\:|\\|\/)+", RegexOptions.Compiled);
@@ -401,7 +401,7 @@ namespace NzbDrone.Core.Parser
return null;
}
public static string ToUrlSlug(string value, bool invalidDashReplacement = false, string trimEndChars = "-_", string deduplicateChars = "-_")
public static string ToUrlSlug(string value)
{
//First to lower case
value = value.ToLowerInvariant();
@@ -412,23 +412,14 @@ namespace NzbDrone.Core.Parser
//Replace spaces
value = Regex.Replace(value, @"\s", "-", RegexOptions.Compiled);
//Should invalid characters be replaced with dash or empty string?
string replaceCharacter = invalidDashReplacement ? "-" : string.Empty;
//Remove invalid chars
value = Regex.Replace(value, @"[^a-z0-9\s-_]", replaceCharacter, RegexOptions.Compiled);
value = Regex.Replace(value, @"[^a-z0-9\s-_]", "", RegexOptions.Compiled);
//Trim dashes or underscores from end, or user defined character set
if (!string.IsNullOrEmpty(trimEndChars))
{
value = value.Trim(trimEndChars.ToCharArray());
}
//Trim dashes from end
value = value.Trim('-', '_');
//Replace double occurrences of - or _, or user defined character set
if (!string.IsNullOrEmpty(deduplicateChars))
{
value = Regex.Replace(value, @"([" + deduplicateChars + "]){2,}", "$1", RegexOptions.Compiled);
}
//Replace double occurences of - or _
value = Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return value;
}

View File

@@ -5,24 +5,24 @@
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="Equ" Version="2.3.0" />
<PackageReference Include="FluentMigrator.Runner.Postgres" Version="3.3.2" />
<PackageReference Include="MailKit" Version="2.15.0" />
<PackageReference Include="Npgsql" Version="6.0.3" />
<PackageReference Include="Servarr.FFMpegCore" Version="4.7.0-26" />
<PackageReference Include="Servarr.FFprobe" Version="5.0.1.93" />
<PackageReference Include="System.Memory" Version="4.5.5" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Servarr.FluentMigrator.Runner" Version="3.3.2.9" />
<PackageReference Include="Servarr.FluentMigrator.Runner.SQLite" Version="3.3.2.9" />
<PackageReference Include="Servarr.FluentMigrator.Runner.Postgres" Version="3.3.2.9" />
<PackageReference Include="FluentMigrator.Runner" Version="3.3.2" />
<PackageReference Include="FluentMigrator.Runner.SQLite" Version="3.3.2" />
<PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="NLog" Version="5.0.1" />
<PackageReference Include="System.Data.SQLite.Core.Servarr" Version="1.0.115.5-18" />
<PackageReference Include="MonoTorrent" Version="2.0.5" />
<PackageReference Include="System.Text.Json" Version="6.0.5" />
<PackageReference Include="System.Text.Json" Version="6.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Common\Radarr.Common.csproj" />

View File

@@ -148,18 +148,12 @@ namespace NzbDrone.Core.RootFolders
var possibleMovieFolders = _diskProvider.GetDirectories(path).ToList();
var unmappedFolders = possibleMovieFolders.Except(moviePaths.Select(s => s.Value), PathEqualityComparer.Instance).ToList();
var recycleBinPath = _configService.RecycleBin;
foreach (var unmappedFolder in unmappedFolders)
foreach (string unmappedFolder in unmappedFolders)
{
var di = new DirectoryInfo(unmappedFolder.Normalize());
if ((!di.Attributes.HasFlag(FileAttributes.System) && !di.Attributes.HasFlag(FileAttributes.Hidden)) || di.Attributes.ToString() == "-1")
{
if (string.IsNullOrWhiteSpace(recycleBinPath) || di.FullName.PathNotEquals(recycleBinPath))
{
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
}
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
}
}

View File

@@ -4,7 +4,7 @@
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="6.0.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Test.Common\Radarr.Test.Common.csproj" />

View File

@@ -53,25 +53,9 @@ namespace Radarr.Api.V3.Collections
}
[HttpGet]
public List<CollectionResource> GetCollections(int? tmdbId)
public List<CollectionResource> GetCollections()
{
var collectionResources = new List<CollectionResource>();
if (tmdbId.HasValue)
{
var collection = _collectionService.FindByTmdbId(tmdbId.Value);
if (collection != null)
{
collectionResources.AddIfNotNull(MapToResource(collection));
}
}
else
{
collectionResources = MapToResource(_collectionService.GetAllCollections()).ToList();
}
return collectionResources;
return MapToResource(_collectionService.GetAllCollections()).ToList();
}
[RestPutById]

View File

@@ -94,8 +94,6 @@ namespace Radarr.Api.V3.Movies
var translatedTitle = movieTranslation?.Title ?? model.Title;
var translatedOverview = movieTranslation?.Overview ?? model.MovieMetadata.Value.Overview;
var collection = model.MovieMetadata.Value.CollectionTmdbId > 0 ? new MovieCollection { Title = model.MovieMetadata.Value.CollectionTitle, TmdbId = model.MovieMetadata.Value.CollectionTmdbId } : null;
return new MovieResource
{
Id = model.Id,
@@ -143,7 +141,7 @@ namespace Radarr.Api.V3.Movies
MovieFile = movieFile,
YouTubeTrailerId = model.MovieMetadata.Value.YouTubeTrailerId,
Studio = model.MovieMetadata.Value.Studio,
Collection = collection,
Collection = new MovieCollection { Title = model.MovieMetadata.Value.CollectionTitle, TmdbId = model.MovieMetadata.Value.CollectionTmdbId },
Popularity = model.MovieMetadata.Value.Popularity
};
}

View File

@@ -589,16 +589,6 @@
"tags": [
"Collection"
],
"parameters": [
{
"name": "tmdbId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "Success",

View File

@@ -33,7 +33,6 @@ namespace Radarr.Http.Authentication
options.AccessDeniedPath = "/login?loginFailed=true";
options.LoginPath = "/login";
options.ExpireTimeSpan = TimeSpan.FromDays(7);
options.SlidingExpiration = true;
})
.AddApiKey("API", options =>
{

View File

@@ -1,8 +1,5 @@
using System;
using System.Net;
using Microsoft.AspNetCore.Http;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration;
using Radarr.Http.Extensions;
@@ -18,14 +15,17 @@ namespace Radarr.Http.Authentication
public class AuthenticationService : IAuthenticationService
{
private const string AnonymousUser = "Anonymous";
private static readonly Logger _authLogger = LogManager.GetLogger("Auth");
private readonly IUserService _userService;
private static string API_KEY;
private static AuthenticationType AUTH_METHOD;
public AuthenticationService(IConfigFileProvider configFileProvider, IUserService userService)
{
_userService = userService;
API_KEY = configFileProvider.ApiKey;
AUTH_METHOD = configFileProvider.AuthenticationMethod;
}

2090
yarn.lock

File diff suppressed because it is too large Load Diff