mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-27 17:54:34 -04:00
Compare commits
26 Commits
v0.2.0.910
...
v0.2.0.935
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9049566c1 | ||
|
|
0bc61bea38 | ||
|
|
032fc68892 | ||
|
|
33cc228ac1 | ||
|
|
d5832a6a07 | ||
|
|
5f8aeeac17 | ||
|
|
54e57bf16a | ||
|
|
b1f76082b2 | ||
|
|
73fed04228 | ||
|
|
ca3d5c184e | ||
|
|
861962d06c | ||
|
|
5057fcc40f | ||
|
|
78e5fdf3bc | ||
|
|
aab14d02f9 | ||
|
|
eb1c3c8b82 | ||
|
|
4025af7895 | ||
|
|
95ca863697 | ||
|
|
74e0db2829 | ||
|
|
2459ddb6f4 | ||
|
|
3e2e085b6b | ||
|
|
931cdacf66 | ||
|
|
18c622de40 | ||
|
|
53e6fa7cf1 | ||
|
|
4afd3f3bfe | ||
|
|
da425b04b1 | ||
|
|
663ac972cd |
@@ -32,7 +32,7 @@ artifacts:
|
||||
|
||||
cache:
|
||||
- '%USERPROFILE%\.nuget\packages'
|
||||
- node_modules
|
||||
- node_modules -> package.json
|
||||
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
|
||||
3479
src/.idea/.idea.NzbDrone/.idea/contentModel.xml
generated
3479
src/.idea/.idea.NzbDrone/.idea/contentModel.xml
generated
File diff suppressed because it is too large
Load Diff
7
src/.idea/.idea.NzbDrone/.idea/indexLayout.xml
generated
Normal file
7
src/.idea/.idea.NzbDrone/.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ContentModelUserStore">
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
100
src/.idea/.idea.NzbDrone/riderModule.iml
generated
100
src/.idea/.idea.NzbDrone/riderModule.iml
generated
@@ -1,103 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="RIDER_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$/../../../Logo/1024.png">
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Logo/1024.png" isTestSource="false" />
|
||||
</content>
|
||||
<content url="file://$MODULE_DIR$/../../../Logo/64.png">
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../../Logo/64.png" isTestSource="false" />
|
||||
</content>
|
||||
<content url="file://$MODULE_DIR$/../..">
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../.nuget/NuGet.exe" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Common/CommonAssemblyInfo.cs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Common/CommonVersionInfo.cs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Common/GlobalSuppressions.cs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../ExternalModules/CurlSharp/CurlSharp" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/MediaInfo/libmediainfo.0.dylib" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/MediaInfo/MediaInfo.dll" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/Sqlite/libsqlite3.0.dylib" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Libraries/Sqlite/sqlite3.dll" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../LogentriesCore" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../LogentriesNLog" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Marr.Data" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Core" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Owin" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../MonoTorrent" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Api" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Api.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.App.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Automation.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Common" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Common.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Console" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Core" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Core.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Host" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Integration.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Libraries.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.SignalR" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Common" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Dummy" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Update" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Update.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows.Test" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceInstall" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceUninstall" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../ExternalModules/CurlSharp/CurlSharp/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../ExternalModules/CurlSharp/CurlSharp/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesCore/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesCore/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesNLog/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../LogentriesNLog/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../Marr.Data/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Core/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Core/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Owin/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../Microsoft.AspNet.SignalR.Owin/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../MonoTorrent/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Api.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Api.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Api/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.App.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.App.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Automation.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Automation.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Common.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Common.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Common/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Console/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Core.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Core.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Core/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Host/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Integration.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Integration.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Libraries.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Libraries.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Mono/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.SignalR/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Common/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Common/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Dummy/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Test.Dummy/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Update.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Update.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Update/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows.Test/bin" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows.Test/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone.Windows/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../NzbDrone/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceInstall/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../ServiceHelpers/ServiceUninstall/obj" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../_ReSharper.Caches/ReSharperHost8.NzbDrone.00" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/../../packages" />
|
||||
</content>
|
||||
<content url="file://$MODULE_DIR$/../../../Logo/1024.png" />
|
||||
<content url="file://$MODULE_DIR$/../../../Logo/64.png" />
|
||||
<content url="file://$MODULE_DIR$/../.." />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -41,6 +41,16 @@ namespace NzbDrone.Api.ClientSchema
|
||||
};
|
||||
|
||||
var value = propertyInfo.GetValue(model, null);
|
||||
|
||||
if (propertyInfo.PropertyType.HasAttribute<FlagsAttribute>())
|
||||
{
|
||||
int intVal = (int)value;
|
||||
value = Enum.GetValues(propertyInfo.PropertyType)
|
||||
.Cast<int>()
|
||||
.Where(f=> (f & intVal) == f)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
field.Value = value;
|
||||
@@ -131,6 +141,12 @@ namespace NzbDrone.Api.ClientSchema
|
||||
|
||||
propertyInfo.SetValue(target, value, null);
|
||||
}
|
||||
|
||||
else if (propertyInfo.PropertyType.HasAttribute<FlagsAttribute>())
|
||||
{
|
||||
int value = field.Value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s)).Sum();
|
||||
propertyInfo.SetValue(target, value, null);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Movie;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Common.Crypto;
|
||||
@@ -16,8 +17,9 @@ namespace NzbDrone.Api.ManualImport
|
||||
public string Name { get; set; }
|
||||
public long Size { get; set; }
|
||||
public SeriesResource Series { get; set; }
|
||||
public MovieResource Movie { get; set; }
|
||||
public int? SeasonNumber { get; set; }
|
||||
public List<EpisodeResource> Episodes { get; set; }
|
||||
public List<Episodes.EpisodeResource> Episodes { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public int QualityWeight { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
@@ -39,6 +41,7 @@ namespace NzbDrone.Api.ManualImport
|
||||
Name = model.Name,
|
||||
Size = model.Size,
|
||||
Series = model.Series.ToResource(),
|
||||
Movie = model.Movie.ToResource(),
|
||||
SeasonNumber = model.SeasonNumber,
|
||||
Episodes = model.Episodes.ToResource(),
|
||||
Quality = model.Quality,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
@@ -9,6 +9,7 @@ namespace NzbDrone.Api.RootFolders
|
||||
{
|
||||
public string Path { get; set; }
|
||||
public long? FreeSpace { get; set; }
|
||||
public long? TotalSpace { get; set; }
|
||||
|
||||
public List<UnmappedFolder> UnmappedFolders { get; set; }
|
||||
}
|
||||
@@ -25,6 +26,7 @@ namespace NzbDrone.Api.RootFolders
|
||||
|
||||
Path = model.Path,
|
||||
FreeSpace = model.FreeSpace,
|
||||
TotalSpace = model.TotalSpace,
|
||||
UnmappedFolders = model.UnmappedFolders
|
||||
};
|
||||
}
|
||||
@@ -48,4 +50,4 @@ namespace NzbDrone.Api.RootFolders
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,6 +245,25 @@ namespace NzbDrone.Common.Disk
|
||||
File.Move(source, destination);
|
||||
}
|
||||
|
||||
public void MoveFolder(string source, string destination, bool overwrite = false)
|
||||
{
|
||||
Ensure.That(source, () => source).IsValidPath();
|
||||
Ensure.That(destination, () => destination).IsValidPath();
|
||||
|
||||
if (source.PathEquals(destination))
|
||||
{
|
||||
throw new IOException(string.Format("Source and destination can't be the same {0}", source));
|
||||
}
|
||||
|
||||
if (FolderExists(destination) && overwrite)
|
||||
{
|
||||
DeleteFolder(destination, true);
|
||||
}
|
||||
|
||||
RemoveReadOnlyFolder(source);
|
||||
Directory.Move(source, destination);
|
||||
}
|
||||
|
||||
public abstract bool TryCreateHardLink(string source, string destination);
|
||||
|
||||
public void DeleteFolder(string path, bool recursive)
|
||||
@@ -371,6 +390,20 @@ namespace NzbDrone.Common.Disk
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveReadOnlyFolder(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
|
||||
if (dirInfo.Attributes.HasFlag(FileAttributes.ReadOnly))
|
||||
{
|
||||
var newAttributes = dirInfo.Attributes & ~(FileAttributes.ReadOnly);
|
||||
dirInfo.Attributes = newAttributes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FileAttributes GetFileAttributes(string path)
|
||||
{
|
||||
return File.GetAttributes(path);
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace NzbDrone.Common.Disk
|
||||
void DeleteFile(string path);
|
||||
void CopyFile(string source, string destination, bool overwrite = false);
|
||||
void MoveFile(string source, string destination, bool overwrite = false);
|
||||
void MoveFolder(string source, string destination, bool overwrite = false);
|
||||
bool TryCreateHardLink(string source, string destination);
|
||||
void DeleteFolder(string path, bool recursive);
|
||||
string ReadAllText(string filePath);
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
|
||||
result.IsLocalhost.Should().BeTrue();
|
||||
result.OutputRootFolders.Should().NotBeNull();
|
||||
result.OutputRootFolders.First().Should().Be(@"/remote/mount/tv");
|
||||
result.OutputRootFolders.First().Should().Be(@"/remote/mount/movie");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -544,7 +544,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
||||
public void should_test_failed_if_tv_sorting_contains_category()
|
||||
{
|
||||
_config.Misc.enable_tv_sorting = true;
|
||||
_config.Misc.tv_categories = new[] { "tv" };
|
||||
_config.Misc.tv_categories = new[] { "movie" };
|
||||
|
||||
var result = new NzbDroneValidationResult(Subject.Test());
|
||||
|
||||
|
||||
@@ -328,7 +328,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
|
||||
|
||||
result.IsLocalhost.Should().BeTrue();
|
||||
result.OutputRootFolders.Should().NotBeNull();
|
||||
result.OutputRootFolders.First().Should().Be(@"C:\Downloads\Finished\utorrent\tv".AsOsAgnostic());
|
||||
result.OutputRootFolders.First().Should().Be(@"C:\Downloads\Finished\utorrent\movie".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
Subject.ConvertToLocalUrls(12, covers);
|
||||
|
||||
|
||||
covers.Single().Url.Should().Be("/MediaCover/12/banner.jpg?lastWrite=1234");
|
||||
covers.Single().Url.Should().Be("/MediaCover/12/banner.jpg");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -14,6 +14,7 @@ using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using FluentAssertions;
|
||||
using NzbDrone.Core.Download;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
@@ -77,7 +78,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<ParsedMovieInfo>(), It.IsAny<bool>()),
|
||||
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), It.IsAny<ParsedMovieInfo>(), It.IsAny<bool>()),
|
||||
Times.Never());
|
||||
|
||||
VerifyNoImport();
|
||||
@@ -128,7 +129,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
imported.Add(new ImportDecision(localMovie));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedMovie>()
|
||||
@@ -154,7 +155,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
imported.Add(new ImportDecision(localMovie));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedMovie>()
|
||||
@@ -226,7 +227,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
imported.Add(new ImportDecision(localMovie));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedMovie>()
|
||||
@@ -280,7 +281,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
Subject.ProcessPath(fileName);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<ParsedMovieInfo>(), true, false), Times.Once());
|
||||
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), It.IsAny<ParsedMovieInfo>(), true, false), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -304,7 +305,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
var result = Subject.ProcessPath(fileName);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true, false), Times.Once());
|
||||
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true, false), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -337,7 +338,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||
imported.Add(new ImportDecision(localMovie));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedEpisodes>()
|
||||
|
||||
@@ -38,8 +38,8 @@ namespace NzbDrone.Core.Test.NetImport
|
||||
|
||||
var result = Subject.Fetch();
|
||||
|
||||
result.First().Title.Should().Be("Think Like a Man Too");
|
||||
result.First().ImdbId.Should().Be("tt2239832");
|
||||
result.Movies.First().Title.Should().Be("Think Like a Man Too");
|
||||
result.Movies.First().ImdbId.Should().Be("tt2239832");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Marr.Data;
|
||||
using Marr.Data.Mapping;
|
||||
@@ -87,7 +87,11 @@ namespace NzbDrone.Core.Datastore
|
||||
RegisterMappers();
|
||||
|
||||
Mapper.Entity<Config>().RegisterModel("Config");
|
||||
Mapper.Entity<RootFolder>().RegisterModel("RootFolders").Ignore(r => r.FreeSpace);
|
||||
|
||||
Mapper.Entity<RootFolder>().RegisterModel("RootFolders")
|
||||
.Ignore(r => r.FreeSpace)
|
||||
.Ignore(r => r.TotalSpace);
|
||||
|
||||
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
||||
|
||||
Mapper.Entity<IndexerDefinition>().RegisterDefinition("Indexers")
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.Search
|
||||
{
|
||||
public class RequiredIndexerFlagsSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IIndexerFactory _indexerFactory;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RequiredIndexerFlagsSpecification(IIndexerFactory indexerFactory, Logger logger)
|
||||
{
|
||||
_indexerFactory = indexerFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
//public SpecificationPriority Priority => SpecificationPriority.Default;
|
||||
public RejectionType Type => RejectionType.Permanent;
|
||||
|
||||
|
||||
public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var torrentInfo = remoteEpisode.Release as TorrentInfo;
|
||||
|
||||
if (torrentInfo == null || torrentInfo.IndexerId == 0)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
IndexerDefinition indexer;
|
||||
try
|
||||
{
|
||||
indexer = _indexerFactory.Get(torrentInfo.IndexerId);
|
||||
}
|
||||
catch (ModelNotFoundException)
|
||||
{
|
||||
_logger.Debug("Indexer with id {0} does not exist, skipping seeders check", torrentInfo.IndexerId);
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings;
|
||||
|
||||
if (torrentIndexerSettings != null)
|
||||
{
|
||||
var minimumSeeders = torrentIndexerSettings.MinimumSeeders;
|
||||
|
||||
if (torrentInfo.Seeders.HasValue && torrentInfo.Seeders.Value < minimumSeeders)
|
||||
{
|
||||
_logger.Debug("Not enough seeders: {0}. Minimum seeders: {1}", torrentInfo.Seeders, minimumSeeders);
|
||||
return Decision.Reject("Not enough seeders: {0}. Minimum seeders: {1}", torrentInfo.Seeders, minimumSeeders);
|
||||
}
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(RemoteMovie remoteEpisode, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var torrentInfo = remoteEpisode.Release;
|
||||
|
||||
|
||||
if (torrentInfo == null || torrentInfo.IndexerId == 0)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
IndexerDefinition indexer;
|
||||
try
|
||||
{
|
||||
indexer = _indexerFactory.Get(torrentInfo.IndexerId);
|
||||
}
|
||||
catch (ModelNotFoundException)
|
||||
{
|
||||
_logger.Debug("Indexer with id {0} does not exist, skipping seeders check", torrentInfo.IndexerId);
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings;
|
||||
|
||||
if (torrentIndexerSettings != null)
|
||||
{
|
||||
var requiredFlags = torrentIndexerSettings.RequiredFlags;
|
||||
var requiredFlag = (IndexerFlags) 0;
|
||||
|
||||
if (requiredFlags == null || requiredFlags.Count() == 0)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
foreach (var flag in requiredFlags)
|
||||
{
|
||||
if (torrentInfo.IndexerFlags.HasFlag((IndexerFlags)flag))
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
requiredFlag |= (IndexerFlags)flag;
|
||||
}
|
||||
|
||||
_logger.Debug("None of the required indexer flags {0} where found. Found flags: {1}", requiredFlag, torrentInfo.IndexerFlags);
|
||||
return Decision.Reject("None of the required indexer flags {0} where found. Found flags: {1}", requiredFlag, torrentInfo.IndexerFlags);
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,19 +27,13 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
|
||||
|
||||
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
|
||||
{
|
||||
var onlyInternal = "";
|
||||
if (Settings.Internal)
|
||||
{
|
||||
onlyInternal = "&internal=true";
|
||||
}
|
||||
|
||||
if (searchParameters != null)
|
||||
{
|
||||
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=imdbsearch&passkey={Settings.Passkey.Trim()}&imdb={searchParameters}", HttpAccept.Rss);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=latestmovies&passkey={Settings.Passkey.Trim()}{onlyInternal}", HttpAccept.Rss);
|
||||
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=latestmovies&passkey={Settings.Passkey.Trim()}", HttpAccept.Rss);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using FluentValidation;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
@@ -30,11 +32,11 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
|
||||
[FieldDefinition(1, Label = "Passkey")]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Require Internal", HelpText = "Will only include internal releases for RSS Sync.")]
|
||||
public bool Internal { get; set; }
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
[FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -82,15 +82,6 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
});
|
||||
}
|
||||
|
||||
// order by internal
|
||||
if (_settings.PreferInternal)
|
||||
{
|
||||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Internal ? 0 : 1)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -63,12 +63,6 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
query.Codec = Settings.Codecs.ToArray();
|
||||
query.Medium = Settings.Mediums.ToArray();
|
||||
|
||||
// Require Internal only if came from RSS sync
|
||||
if (Settings.RequireInternal && query.ImdbInfo == null)
|
||||
{
|
||||
query.Origin = 1;
|
||||
}
|
||||
|
||||
request.SetContent(query.ToJson());
|
||||
|
||||
yield return new IndexerRequest(request);
|
||||
|
||||
@@ -6,6 +6,7 @@ using NzbDrone.Core.Validation;
|
||||
using System.Linq.Expressions;
|
||||
using FluentValidation.Results;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.HDBits
|
||||
{
|
||||
@@ -41,23 +42,20 @@ namespace NzbDrone.Core.Indexers.HDBits
|
||||
[FieldDefinition(2, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since your API key will be sent to that host.")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Prefer Internal", Type = FieldType.Checkbox, HelpText = "Favors Internal releases over all other releases.")]
|
||||
public bool PreferInternal { get; set; }
|
||||
|
||||
[FieldDefinition(4, Label = "Require Internal", Type = FieldType.Checkbox, HelpText = "Require Internal releases for release to be accepted.")]
|
||||
public bool RequireInternal { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "Categories", Type = FieldType.Tag, SelectOptions = typeof(HdBitsCategory), Advanced = true, HelpText = "Options: Movie, TV, Documentary, Music, Sport, Audio, XXX, MiscDemo. If unspecified, all options are used.")]
|
||||
[FieldDefinition(3, Label = "Categories", Type = FieldType.Tag, SelectOptions = typeof(HdBitsCategory), Advanced = true, HelpText = "Options: Movie, TV, Documentary, Music, Sport, Audio, XXX, MiscDemo. If unspecified, all options are used.")]
|
||||
public IEnumerable<int> Categories { get; set; }
|
||||
|
||||
[FieldDefinition(6, Label = "Codecs", Type = FieldType.Tag, SelectOptions = typeof(HdBitsCodec), Advanced = true, HelpText = "Options: h264, Mpeg2, VC1, Xvid. If unspecified, all options are used.")]
|
||||
[FieldDefinition(4, Label = "Codecs", Type = FieldType.Tag, SelectOptions = typeof(HdBitsCodec), Advanced = true, HelpText = "Options: h264, Mpeg2, VC1, Xvid. If unspecified, all options are used.")]
|
||||
public IEnumerable<int> Codecs { get; set; }
|
||||
|
||||
[FieldDefinition(7, Label = "Mediums", Type = FieldType.Tag, SelectOptions = typeof(HdBitsMedium), Advanced = true, HelpText = "Options: BluRay, Encode, Capture, Remux, WebDL. If unspecified, all options are used.")]
|
||||
[FieldDefinition(5, Label = "Mediums", Type = FieldType.Tag, SelectOptions = typeof(HdBitsMedium), Advanced = true, HelpText = "Options: BluRay, Encode, Capture, Remux, WebDL. If unspecified, all options are used.")]
|
||||
public IEnumerable<int> Mediums { get; set; }
|
||||
|
||||
[FieldDefinition(8, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
[FieldDefinition(6, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(7, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
@@ -36,6 +38,9 @@ namespace NzbDrone.Core.Indexers.IPTorrents
|
||||
|
||||
[FieldDefinition(1, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(2, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
namespace NzbDrone.Core.Indexers
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
{
|
||||
public interface ITorrentIndexerSettings : IIndexerSettings
|
||||
{
|
||||
int MinimumSeeders { get; set; }
|
||||
IEnumerable<int> RequiredFlags { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Validation;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Nyaa
|
||||
{
|
||||
public class NyaaSettingsValidator : AbstractValidator<NyaaSettings>
|
||||
@@ -32,6 +35,9 @@ namespace NzbDrone.Core.Indexers.Nyaa
|
||||
|
||||
[FieldDefinition(2, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -73,8 +73,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
}
|
||||
|
||||
// Only add approved torrents
|
||||
if (_settings.RequireApproved && torrent.Checked)
|
||||
{
|
||||
|
||||
torrentInfos.Add(new PassThePopcornInfo()
|
||||
{
|
||||
Guid = string.Format("PassThePopcorn-{0}", id),
|
||||
@@ -91,67 +90,10 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
ImdbId = (result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0),
|
||||
IndexerFlags = flags
|
||||
});
|
||||
}
|
||||
|
||||
// Add all torrents
|
||||
else if (!_settings.RequireApproved)
|
||||
{
|
||||
torrentInfos.Add(new PassThePopcornInfo()
|
||||
{
|
||||
Guid = string.Format("PassThePopcorn-{0}", id),
|
||||
Title = title,
|
||||
Size = long.Parse(torrent.Size),
|
||||
DownloadUrl = GetDownloadUrl(id, jsonResponse.AuthKey, jsonResponse.PassKey),
|
||||
InfoUrl = GetInfoUrl(result.GroupId, id),
|
||||
Seeders = int.Parse(torrent.Seeders),
|
||||
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
|
||||
PublishDate = torrent.UploadTime.ToUniversalTime(),
|
||||
Golden = torrent.GoldenPopcorn,
|
||||
Scene = torrent.Scene,
|
||||
Approved = torrent.Checked,
|
||||
ImdbId = (result.ImdbId.IsNotNullOrWhiteSpace() ? int.Parse(result.ImdbId) : 0),
|
||||
IndexerFlags = flags
|
||||
});
|
||||
}
|
||||
// Don't add any torrents
|
||||
else if (_settings.RequireApproved && !torrent.Checked)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prefer golden
|
||||
if (_settings.Golden)
|
||||
{
|
||||
if (_settings.Scene)
|
||||
{
|
||||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Golden ? 0 : 1)
|
||||
.ThenBy(o => ((dynamic)o).Scene ? 0 : 1)
|
||||
.ToArray();
|
||||
}
|
||||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Golden ? 0 : 1)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// prefer scene
|
||||
if (_settings.Scene)
|
||||
{
|
||||
return
|
||||
torrentInfos.OrderByDescending(o => o.PublishDate)
|
||||
.ThenBy(o => ((dynamic)o).Scene ? 0 : 1)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
// order by date
|
||||
return
|
||||
torrentInfos
|
||||
.OrderByDescending(o => o.PublishDate)
|
||||
.ToArray();
|
||||
torrentInfos;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,8 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
var filter = "";
|
||||
if (searchParameters == null)
|
||||
{
|
||||
if (Settings.RequireGolden)
|
||||
{
|
||||
filter = "&scene=2";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
var request =
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using FluentValidation;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
{
|
||||
@@ -39,20 +41,11 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
|
||||
[FieldDefinition(3, Label = "Passkey", HelpText = "PTP Passkey")]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
[FieldDefinition(4, Label = "Prefer Golden", Type = FieldType.Checkbox , HelpText = "Favors Golden Popcorn-releases over all other releases.")]
|
||||
public bool Golden { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "Prefer Scene", Type = FieldType.Checkbox, HelpText = "Favors scene-releases over non-scene releases.")]
|
||||
public bool Scene { get; set; }
|
||||
|
||||
[FieldDefinition(6, Label = "Require Approved", Type = FieldType.Checkbox, HelpText = "Require staff-approval for releases to be accepted.")]
|
||||
public bool RequireApproved { get; set; }
|
||||
|
||||
[FieldDefinition(7, Label = "Require Golden", Type = FieldType.Checkbox, HelpText = "Require Golden Popcorn-releases for releases to be accepted.")]
|
||||
public bool RequireGolden { get; set; }
|
||||
|
||||
[FieldDefinition(8, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
[FieldDefinition(4, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(5, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -29,9 +29,10 @@ namespace NzbDrone.Core.Indexers.Rarbg
|
||||
|
||||
if (jsonResponse.Resource.error_code.HasValue)
|
||||
{
|
||||
if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8)
|
||||
if (jsonResponse.Resource.error_code == 20 || jsonResponse.Resource.error_code == 8
|
||||
|| jsonResponse.Resource.error_code == 9 || jsonResponse.Resource.error_code == 10)
|
||||
{
|
||||
// No results found
|
||||
// No results or imdbid not found
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,15 @@ namespace NzbDrone.Core.Indexers.Rarbg
|
||||
|
||||
requestBuilder.AddQueryParam("mode", "search");
|
||||
|
||||
requestBuilder.AddQueryParam("search_imdb", searchCriteria.Movie.ImdbId);
|
||||
if (searchCriteria.Movie.ImdbId != null)
|
||||
{
|
||||
requestBuilder.AddQueryParam("search_imdb", searchCriteria.Movie.ImdbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
requestBuilder.AddQueryParam("search_string", $"{searchCriteria.Movie.Title} {searchCriteria.Movie.Year}");
|
||||
}
|
||||
|
||||
|
||||
if (!Settings.RankedOnly)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using FluentValidation;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Rarbg
|
||||
@@ -34,6 +36,9 @@ namespace NzbDrone.Core.Indexers.Rarbg
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(4, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
@@ -34,6 +36,9 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(4, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using FluentValidation;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.TorrentRss
|
||||
@@ -34,6 +36,9 @@ namespace NzbDrone.Core.Indexers.TorrentRss
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(4, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Indexers.Newznab;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Torznab
|
||||
@@ -58,6 +60,9 @@ namespace NzbDrone.Core.Indexers.Torznab
|
||||
|
||||
[FieldDefinition(7, Type = FieldType.Textbox, Label = "Minimum Seeders", HelpText = "Minimum number of seeders required.", Advanced = true)]
|
||||
public int MinimumSeeders { get; set; }
|
||||
|
||||
[FieldDefinition(8, Type = FieldType.Tag, SelectOptions = typeof(IndexerFlags), Label = "Required Flags", HelpText = "What indexer flags are required?", Advanced = true)]
|
||||
public IEnumerable<int> RequiredFlags { get; set; }
|
||||
|
||||
public override NzbDroneValidationResult Validate()
|
||||
{
|
||||
|
||||
@@ -161,15 +161,9 @@ namespace NzbDrone.Core.MediaFiles
|
||||
|
||||
if (!_diskProvider.FolderExists(movie.Path))
|
||||
{
|
||||
if (_configService.CreateEmptySeriesFolders &&
|
||||
_diskProvider.FolderExists(rootFolder))
|
||||
{
|
||||
_logger.Debug("Creating missing movies folder: {0}", movie.Path);
|
||||
_diskProvider.CreateFolder(movie.Path);
|
||||
SetPermissions(movie.Path);
|
||||
}
|
||||
else
|
||||
if (movie.MovieFileId != 0)
|
||||
{
|
||||
//Since there is no folder, there can't be any files right?
|
||||
// Delete Movie from MovieFiles
|
||||
_movieFileRepository.Delete(movie.MovieFileId);
|
||||
|
||||
@@ -179,6 +173,13 @@ namespace NzbDrone.Core.MediaFiles
|
||||
|
||||
_logger.Debug("Movies folder doesn't exist: {0}", movie.Path);
|
||||
}
|
||||
else if (_configService.CreateEmptySeriesFolders &&
|
||||
_diskProvider.FolderExists(rootFolder))
|
||||
{
|
||||
_logger.Debug("Creating missing movies folder: {0}", movie.Path);
|
||||
_diskProvider.CreateFolder(movie.Path);
|
||||
SetPermissions(movie.Path);
|
||||
}
|
||||
|
||||
_eventAggregator.PublishEvent(new MovieScanSkippedEvent(movie, MovieScanSkippedReason.MovieFolderDoesNotExist));
|
||||
return;
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
}
|
||||
}
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, folderInfo, true, false);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, null, folderInfo, true, false);
|
||||
var importResults = _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
|
||||
|
||||
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
|
||||
@@ -241,7 +241,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
}
|
||||
}
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, movie, null, true, false);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, movie, null, null, true, false);
|
||||
|
||||
return _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
@@ -7,6 +8,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
Decision IsSatisfiedBy(LocalEpisode localEpisode);
|
||||
|
||||
Decision IsSatisfiedBy(LocalMovie localMovie);
|
||||
Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,16 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
_logger.Debug("Decisions: {0}", decisions.Count);
|
||||
|
||||
//I added a null op for the rare case that the quality is null. TODO: find out why that would even happen in the first place.
|
||||
var qualifiedImports = decisions.Where(c => c.Approved)
|
||||
.GroupBy(c => c.LocalMovie.Movie.Id, (i, s) => s
|
||||
.OrderByDescending(c => c.LocalMovie.Quality, new QualityModelComparer(s.First().LocalMovie.Movie.Profile))
|
||||
.OrderByDescending(c => c.LocalMovie.Quality ?? new QualityModel{Quality = Quality.Unknown}, new QualityModelComparer(s.First().LocalMovie.Movie.Profile))
|
||||
.ThenByDescending(c => c.LocalMovie.Size))
|
||||
.SelectMany(c => c)
|
||||
.ToList();
|
||||
|
||||
|
||||
|
||||
var importResults = new List<ImportResult>();
|
||||
|
||||
foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalMovie.Size)
|
||||
|
||||
@@ -6,6 +6,7 @@ using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
@@ -20,8 +21,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, bool shouldCheckQuality);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource);
|
||||
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
|
||||
}
|
||||
|
||||
@@ -62,12 +63,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie)
|
||||
{
|
||||
return GetImportDecisions(videoFiles, movie, null, true, false);
|
||||
return GetImportDecisions(videoFiles, movie, null, null, true, false);
|
||||
}
|
||||
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, bool shouldCheckQuality = false)
|
||||
{
|
||||
return GetImportDecisions(videoFiles, movie, null, true, shouldCheckQuality);
|
||||
return GetImportDecisions(videoFiles, movie, null, null, true, shouldCheckQuality);
|
||||
}
|
||||
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
|
||||
@@ -87,7 +88,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
return decisions;
|
||||
}
|
||||
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource)
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource)
|
||||
{
|
||||
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie);
|
||||
|
||||
@@ -98,13 +99,13 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
decisions.AddIfNotNull(GetDecision(file, movie, folderInfo, sceneSource, shouldUseFolderName));
|
||||
decisions.AddIfNotNull(GetDecision(file, movie, downloadClientItem, folderInfo, sceneSource, shouldUseFolderName));
|
||||
}
|
||||
|
||||
return decisions;
|
||||
}
|
||||
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality = false)
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality)
|
||||
{
|
||||
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie);
|
||||
|
||||
@@ -115,13 +116,13 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
|
||||
foreach (var file in newFiles)
|
||||
{
|
||||
decisions.AddIfNotNull(GetDecision(file, movie, folderInfo, sceneSource, shouldUseFolderName, shouldCheckQuality));
|
||||
decisions.AddIfNotNull(GetDecision(file, movie, downloadClientItem, folderInfo, sceneSource, shouldUseFolderName, shouldCheckQuality));
|
||||
}
|
||||
|
||||
return decisions;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(string file, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName, bool shouldCheckQuality = false)
|
||||
private ImportDecision GetDecision(string file, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName, bool shouldCheckQuality = false)
|
||||
{
|
||||
ImportDecision decision = null;
|
||||
|
||||
@@ -283,11 +284,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
|
||||
|
||||
|
||||
decision = GetDecision(localMovie);
|
||||
decision = GetDecision(localMovie, downloadClientItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
decision = GetDecision(localMovie);
|
||||
decision = GetDecision(localMovie, downloadClientItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,9 +315,9 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
return decision;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(LocalMovie localMovie)
|
||||
private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var reasons = _specifications.Select(c => EvaluateSpec(c, localMovie))
|
||||
var reasons = _specifications.Select(c => EvaluateSpec(c, localMovie, downloadClientItem))
|
||||
.Where(c => c != null);
|
||||
|
||||
return new ImportDecision(localMovie, reasons.ToArray());
|
||||
@@ -385,11 +386,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
return new ImportDecision(localEpisode, reasons.ToArray());
|
||||
}
|
||||
|
||||
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalMovie localMovie)
|
||||
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = spec.IsSatisfiedBy(localMovie);
|
||||
var result = spec.IsSatisfiedBy(localMovie, downloadClientItem);
|
||||
|
||||
if (!result.Accepted)
|
||||
{
|
||||
|
||||
@@ -104,13 +104,19 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
|
||||
private List<ManualImportItem> ProcessFolder(string folder, string downloadId)
|
||||
{
|
||||
DownloadClientItem downloadClientItem = null;
|
||||
var directoryInfo = new DirectoryInfo(folder);
|
||||
var series = _parsingService.GetMovie(directoryInfo.Name);
|
||||
|
||||
if (series == null && downloadId.IsNotNullOrWhiteSpace())
|
||||
if (downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
series = trackedDownload.RemoteMovie.Movie;
|
||||
downloadClientItem = trackedDownload.DownloadItem;
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
series = trackedDownload.RemoteMovie.Movie;
|
||||
}
|
||||
}
|
||||
|
||||
if (series == null)
|
||||
@@ -122,7 +128,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
|
||||
var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name, _config.ParsingLeniency > 0);
|
||||
var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList();
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder), false);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, downloadClientItem, folderInfo, SceneSource(series, folder), false);
|
||||
|
||||
return decisions.Select(decision => MapItem(decision, folder, downloadId)).ToList();
|
||||
}
|
||||
@@ -134,6 +140,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
folder = new FileInfo(file).Directory.FullName;
|
||||
}
|
||||
|
||||
DownloadClientItem downloadClientItem = null;
|
||||
var relativeFile = folder.GetRelativePath(file);
|
||||
|
||||
var movie = _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]);
|
||||
@@ -143,10 +150,15 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
movie = _parsingService.GetMovie(relativeFile);
|
||||
}
|
||||
|
||||
if (movie == null && downloadId.IsNotNullOrWhiteSpace())
|
||||
if (downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
movie = trackedDownload.RemoteMovie.Movie;
|
||||
downloadClientItem = trackedDownload.DownloadItem;
|
||||
|
||||
if (movie == null)
|
||||
{
|
||||
movie = trackedDownload.RemoteMovie.Movie;
|
||||
}
|
||||
}
|
||||
|
||||
if (movie == null)
|
||||
@@ -162,7 +174,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
}
|
||||
|
||||
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> { file },
|
||||
movie, null, SceneSource(movie, folder), true);
|
||||
movie, downloadClientItem, null, SceneSource(movie, folder), true);
|
||||
|
||||
return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : new ManualImportItem
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
@@ -64,7 +65,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie)
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (_configService.SkipFreeSpaceCheckWhenImporting)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
@@ -24,7 +25,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie)
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
public class GrabbedReleaseQualitySpecification : IImportDecisionEngineSpecification
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly IHistoryService _historyService;
|
||||
|
||||
public GrabbedReleaseQualitySpecification(Logger logger, IHistoryService historyService)
|
||||
{
|
||||
_logger = logger;
|
||||
_historyService = historyService;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile);
|
||||
if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && qualityComparer.Compare(e.EpisodeFile.Value.Quality, localEpisode.Quality) > 0))
|
||||
{
|
||||
_logger.Debug("This file isn't an upgrade for all episodes. Skipping {0}", localEpisode.Path);
|
||||
return Decision.Reject("Not an upgrade for existing episode file(s)");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (downloadClientItem == null)
|
||||
{
|
||||
_logger.Debug("No download client item provided, skipping.");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var grabbedHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
|
||||
.Where(h => h.EventType == HistoryEventType.Grabbed)
|
||||
.ToList();
|
||||
|
||||
if (grabbedHistory.Empty())
|
||||
{
|
||||
_logger.Debug("No grabbed history for this download client item");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var parsedReleaseName = Parser.Parser.ParseTitle(grabbedHistory.First().SourceTitle);
|
||||
|
||||
if (parsedReleaseName != null && parsedReleaseName.FullSeason)
|
||||
{
|
||||
_logger.Debug("File is part of a season pack, skipping.");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
foreach (var item in grabbedHistory)
|
||||
{
|
||||
if (item.Quality.Quality != Quality.Unknown && item.Quality != localEpisode.Quality)
|
||||
{
|
||||
_logger.Debug("Quality for grabbed release ({0}) does not match the quality of the file ({1})", item.Quality, localEpisode.Quality);
|
||||
return Decision.Reject("File quality does not match quality of the grabbed release");
|
||||
}
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
@@ -16,7 +17,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie)
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (localMovie.ExistingFile)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
@@ -38,7 +39,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode)
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var sample = _detectSample.IsSample(localEpisode.Movie,
|
||||
localEpisode.Quality,
|
||||
|
||||
@@ -5,6 +5,7 @@ using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
@@ -57,7 +58,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode)
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (localEpisode.ExistingFile)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
@@ -29,7 +30,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
return Decision.Reject("Episode file on disk contains more episodes than this file contains");
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie)
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie)
|
||||
public Decision IsSatisfiedBy(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
@@ -27,7 +28,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode)
|
||||
public Decision IsSatisfiedBy(LocalMovie localEpisode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
EnsureMovieFolder(movieFile, movie, filePath);
|
||||
|
||||
_logger.Debug("Renaming movie file: {0} to {1}", movieFile, filePath);
|
||||
|
||||
|
||||
return TransferFile(movieFile, movie, filePath, TransferMode.Move);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
EnsureMovieFolder(movieFile, localMovie, filePath);
|
||||
|
||||
_logger.Debug("Moving movie file: {0} to {1}", movieFile.Path, filePath);
|
||||
|
||||
|
||||
return TransferFile(movieFile, localMovie.Movie, filePath, TransferMode.Move);
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
_logger.Debug("Copying movie file: {0} to {1}", movieFile.Path, filePath);
|
||||
return TransferFile(movieFile, localMovie.Movie, filePath, TransferMode.Copy);
|
||||
}
|
||||
|
||||
|
||||
private MovieFile TransferFile(MovieFile movieFile, Movie movie, string destinationFilePath, TransferMode mode)
|
||||
{
|
||||
Ensure.That(movieFile, () => movieFile).IsNotNull();
|
||||
@@ -122,11 +122,8 @@ namespace NzbDrone.Core.MediaFiles
|
||||
var oldMoviePath = movie.Path;
|
||||
|
||||
var newMoviePath = new OsPath(destinationFilePath).Directory.FullPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
movie.Path = newMoviePath;
|
||||
if (oldMoviePath != newMoviePath)
|
||||
{
|
||||
_movieService.UpdateMovie(movie);
|
||||
}
|
||||
|
||||
movie.Path = newMoviePath; //We update it when everything went well!
|
||||
|
||||
movieFile.RelativePath = movie.Path.GetRelativePath(destinationFilePath);
|
||||
|
||||
@@ -146,12 +143,35 @@ namespace NzbDrone.Core.MediaFiles
|
||||
|
||||
if(oldMoviePath != newMoviePath)
|
||||
{
|
||||
//Let's move the old files before deleting the old folder. We could just do move folder, but the main file (movie file) is already moved, so eh.
|
||||
var files = _diskProvider.GetFiles(oldMoviePath, SearchOption.AllDirectories);
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
try
|
||||
{
|
||||
var destFile = Path.Combine(newMoviePath, oldMoviePath.GetRelativePath(file));
|
||||
_diskProvider.EnsureFolder(Path.GetDirectoryName(destFile));
|
||||
_diskProvider.MoveFile(file, destFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Error while trying to move extra file {0} to new folder. Maybe it already exists? (Manual cleanup necessary!).", oldMoviePath.GetRelativePath(file));
|
||||
}
|
||||
}
|
||||
|
||||
if (_diskProvider.GetFiles(oldMoviePath, SearchOption.AllDirectories).Count() == 0)
|
||||
{
|
||||
_recycleBinProvider.DeleteFolder(oldMoviePath);
|
||||
}
|
||||
}
|
||||
|
||||
//Only update the movie path if we were successfull!
|
||||
if (oldMoviePath != newMoviePath)
|
||||
{
|
||||
_movieService.UpdateMovie(movie);
|
||||
}
|
||||
|
||||
return movieFile;
|
||||
}
|
||||
|
||||
@@ -163,7 +183,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
private void EnsureMovieFolder(MovieFile movieFile, Movie movie, string filePath)
|
||||
{
|
||||
var movieFolder = Path.GetDirectoryName(filePath);
|
||||
movie.Path = movieFolder;
|
||||
//movie.Path = movieFolder;
|
||||
var rootFolder = new OsPath(movieFolder).Directory.FullPath;
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||
private readonly Logger _logger;
|
||||
|
||||
|
||||
public RenameMovieFileService(IMovieService movieService,
|
||||
IMediaFileService mediaFileService,
|
||||
IMoveMovieFiles movieFileMover,
|
||||
@@ -91,7 +91,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void RenameFiles(List<MovieFile> movieFiles, Movie movie, string oldMoviePath = null)
|
||||
@@ -136,23 +136,25 @@ namespace NzbDrone.Core.MediaFiles
|
||||
var newFolder = _filenameBuilder.BuildMoviePath(movie);
|
||||
if (newFolder != movie.Path && movie.PathState == MoviePathState.Dynamic)
|
||||
{
|
||||
|
||||
|
||||
if (!_configService.AutoRenameFolders)
|
||||
{
|
||||
_logger.Info("{0}'s movie should be {1} according to your naming config.", movie, newFolder);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_logger.Info("{0}'s movie folder changed to: {1}", movie, newFolder);
|
||||
var oldFolder = movie.Path;
|
||||
movie.Path = newFolder;
|
||||
|
||||
if (shouldRenameFiles)
|
||||
_diskProvider.MoveFolder(oldFolder, movie.Path);
|
||||
|
||||
if (false)
|
||||
{
|
||||
var movieFiles = _mediaFileService.GetFilesByMovie(movie.Id);
|
||||
_logger.ProgressInfo("Renaming movie files for {0}", movie.Title);
|
||||
RenameFiles(movieFiles, movie, oldFolder);
|
||||
_logger.ProgressInfo("All movie files renamed for {0}", movie.Title);
|
||||
_logger.ProgressInfo("All movie files renamed for {0}", movie.Title);
|
||||
}
|
||||
|
||||
_movieService.UpdateMovie(movie);
|
||||
@@ -162,7 +164,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
_recycleBinProvider.DeleteFolder(oldFolder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (movie.PathState == MoviePathState.StaticOnce)
|
||||
@@ -194,7 +196,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
RenameFiles(movieFiles, movie);
|
||||
_logger.ProgressInfo("All movie files renamed for {0}", movie.Title);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Execute(RenameMovieFolderCommand message)
|
||||
@@ -206,7 +208,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
foreach(var movie in moviesToRename)
|
||||
{
|
||||
var movieFiles = _mediaFileService.GetFilesByMovie(movie.Id);
|
||||
_logger.ProgressInfo("Renaming movie folder for {0}", movie.Title);
|
||||
//_logger.ProgressInfo("Renaming movie folder for {0}", movie.Title);
|
||||
RenameMoviePath(movie);
|
||||
}
|
||||
}
|
||||
@@ -214,7 +216,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
_logger.Warn(ex, "wtf: {0}, {1}", ex.ResultCode, ex.Data);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
var airDate = movie.PhysicalRelease;
|
||||
|
||||
if (airDate == null)
|
||||
if (airDate.HasValue == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
var airDate = movie.InCinemas;
|
||||
|
||||
if (airDate == null)
|
||||
if (airDate.HasValue == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||
|
||||
public Movie GetMovieInfo(int TmdbId, Profile profile = null, bool hasPreDBEntry = false)
|
||||
{
|
||||
var langCode = profile != null ? IsoLanguages.Get(profile.Language).TwoLetterCode : "us";
|
||||
var langCode = profile != null ? IsoLanguages.Get(profile.Language).TwoLetterCode : "en";
|
||||
|
||||
var request = _movieBuilder.Create()
|
||||
.SetSegment("route", "movie")
|
||||
|
||||
@@ -34,19 +34,21 @@ namespace NzbDrone.Core.NetImport
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public override IList<Movie> Fetch()
|
||||
public override NetImportFetchResult Fetch()
|
||||
{
|
||||
var generator = GetRequestGenerator();
|
||||
return FetchMovies(generator.GetMovies());
|
||||
}
|
||||
|
||||
protected virtual IList<Movie> FetchMovies(NetImportPageableRequestChain pageableRequestChain, bool isRecent = false)
|
||||
protected virtual NetImportFetchResult FetchMovies(NetImportPageableRequestChain pageableRequestChain, bool isRecent = false)
|
||||
{
|
||||
var movies = new List<Movie>();
|
||||
var url = string.Empty;
|
||||
|
||||
var parser = GetParser();
|
||||
|
||||
var anyFailure = false;
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < pageableRequestChain.Tiers; i++)
|
||||
@@ -73,6 +75,7 @@ namespace NzbDrone.Core.NetImport
|
||||
}
|
||||
catch (WebException webException)
|
||||
{
|
||||
anyFailure = true;
|
||||
if (webException.Message.Contains("502") || webException.Message.Contains("503") ||
|
||||
webException.Message.Contains("timed out"))
|
||||
{
|
||||
@@ -85,6 +88,7 @@ namespace NzbDrone.Core.NetImport
|
||||
}
|
||||
catch (HttpException httpException)
|
||||
{
|
||||
anyFailure = true;
|
||||
if ((int)httpException.Response.StatusCode == 429)
|
||||
{
|
||||
_logger.Warn("API Request Limit reached for {0}", this);
|
||||
@@ -96,11 +100,12 @@ namespace NzbDrone.Core.NetImport
|
||||
}
|
||||
catch (Exception feedEx)
|
||||
{
|
||||
anyFailure = true;
|
||||
feedEx.Data.Add("FeedUrl", url);
|
||||
_logger.Error(feedEx, "An error occurred while processing feed. " + url);
|
||||
}
|
||||
|
||||
return movies;
|
||||
return new NetImportFetchResult {Movies = movies, AnyFailure = anyFailure};
|
||||
}
|
||||
|
||||
protected virtual IList<Movie> FetchPage(NetImportRequest request, IParseNetImportResponse parser)
|
||||
|
||||
@@ -9,6 +9,6 @@ namespace NzbDrone.Core.NetImport
|
||||
bool Enabled { get; }
|
||||
bool EnableAuto { get; }
|
||||
|
||||
IList<Movie> Fetch();
|
||||
NetImportFetchResult Fetch();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace NzbDrone.Core.NetImport.ImportExclusions
|
||||
public interface IImportExclusionsRepository : IBasicRepository<ImportExclusion>
|
||||
{
|
||||
bool IsMovieExcluded(int tmdbid);
|
||||
ImportExclusion GetByTmdbid(int tmdbid);
|
||||
}
|
||||
|
||||
public class ImportExclusionsRepository : BasicRepository<ImportExclusion>, IImportExclusionsRepository
|
||||
@@ -31,5 +32,10 @@ namespace NzbDrone.Core.NetImport.ImportExclusions
|
||||
{
|
||||
return Query.Where(ex => ex.TmdbId == tmdbid).Any();
|
||||
}
|
||||
|
||||
public ImportExclusion GetByTmdbid(int tmdbid)
|
||||
{
|
||||
return Query.Where(ex => ex.TmdbId == tmdbid).First();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ namespace NzbDrone.Core.NetImport.ImportExclusions
|
||||
|
||||
public ImportExclusion AddExclusion(ImportExclusion exclusion)
|
||||
{
|
||||
if (_exclusionRepository.IsMovieExcluded(exclusion.TmdbId))
|
||||
{
|
||||
return _exclusionRepository.GetByTmdbid(exclusion.TmdbId);
|
||||
}
|
||||
return _exclusionRepository.Insert(exclusion);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,12 @@ using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.NetImport
|
||||
{
|
||||
public class NetImportFetchResult
|
||||
{
|
||||
public IList<Movie> Movies { get; set; }
|
||||
public bool AnyFailure { get; set; }
|
||||
}
|
||||
|
||||
public abstract class NetImportBase<TSettings> : INetImport
|
||||
where TSettings : IProviderConfig, new()
|
||||
{
|
||||
@@ -20,7 +26,7 @@ namespace NzbDrone.Core.NetImport
|
||||
public abstract bool Enabled { get; }
|
||||
public abstract bool EnableAuto { get; }
|
||||
|
||||
public abstract IList<Movie> Fetch();
|
||||
public abstract NetImportFetchResult Fetch();
|
||||
|
||||
public NetImportBase(IConfigService configService, IParsingService parsingService, Logger logger)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace NzbDrone.Core.NetImport
|
||||
{
|
||||
public interface IFetchNetImport
|
||||
{
|
||||
List<Movie> Fetch(int listId, bool onlyEnableAuto);
|
||||
NetImportFetchResult Fetch(int listId, bool onlyEnableAuto);
|
||||
List<Movie> FetchAndFilter(int listId, bool onlyEnableAuto);
|
||||
}
|
||||
|
||||
@@ -54,21 +54,22 @@ namespace NzbDrone.Core.NetImport
|
||||
}
|
||||
|
||||
|
||||
public List<Movie> Fetch(int listId, bool onlyEnableAuto = false)
|
||||
public NetImportFetchResult Fetch(int listId, bool onlyEnableAuto = false)
|
||||
{
|
||||
return MovieListSearch(listId, onlyEnableAuto);
|
||||
}
|
||||
|
||||
public List<Movie> FetchAndFilter(int listId, bool onlyEnableAuto)
|
||||
{
|
||||
var movies = MovieListSearch(listId, onlyEnableAuto);
|
||||
var movies = MovieListSearch(listId, onlyEnableAuto).Movies;
|
||||
|
||||
return _movieService.FilterExistingMovies(movies);
|
||||
return _movieService.FilterExistingMovies(movies.ToList());
|
||||
}
|
||||
|
||||
public List<Movie> MovieListSearch(int listId, bool onlyEnableAuto = false)
|
||||
public NetImportFetchResult MovieListSearch(int listId, bool onlyEnableAuto = false)
|
||||
{
|
||||
var movies = new List<Movie>();
|
||||
var anyFailure = false;
|
||||
|
||||
var importLists = _netImportFactory.GetAvailableProviders();
|
||||
|
||||
@@ -81,24 +82,31 @@ namespace NzbDrone.Core.NetImport
|
||||
|
||||
foreach (var list in lists)
|
||||
{
|
||||
movies.AddRange(list.Fetch());
|
||||
var result = list.Fetch();
|
||||
movies.AddRange(result.Movies);
|
||||
anyFailure |= result.AnyFailure;
|
||||
}
|
||||
|
||||
_logger.Debug("Found {0} movies from list(s) {1}", movies.Count, string.Join(", ", lists.Select(l => l.Definition.Name)));
|
||||
|
||||
return movies.DistinctBy(x => {
|
||||
if (x.TmdbId != 0)
|
||||
{
|
||||
return x.TmdbId.ToString();
|
||||
}
|
||||
return new NetImportFetchResult
|
||||
{
|
||||
Movies = movies.DistinctBy(x =>
|
||||
{
|
||||
if (x.TmdbId != 0)
|
||||
{
|
||||
return x.TmdbId.ToString();
|
||||
}
|
||||
|
||||
if (x.ImdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return x.ImdbId;
|
||||
}
|
||||
if (x.ImdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return x.ImdbId;
|
||||
}
|
||||
|
||||
return x.Title;
|
||||
}).ToList();
|
||||
return x.Title;
|
||||
}).ToList(),
|
||||
AnyFailure = anyFailure
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -112,9 +120,13 @@ namespace NzbDrone.Core.NetImport
|
||||
return;
|
||||
}
|
||||
|
||||
var listedMovies = Fetch(0, true);
|
||||
var result = Fetch(0, true);
|
||||
var listedMovies = result.Movies.ToList();
|
||||
|
||||
CleanLibrary(listedMovies);
|
||||
if (!result.AnyFailure)
|
||||
{
|
||||
CleanLibrary(listedMovies);
|
||||
}
|
||||
|
||||
listedMovies = listedMovies.Where(x => !_movieService.MovieExists(x)).ToList();
|
||||
if (listedMovies.Any())
|
||||
|
||||
@@ -36,19 +36,19 @@ namespace NzbDrone.Core.NetImport.TMDb
|
||||
RuleFor(c => c.Ceritification)
|
||||
.Matches(@"^\bNR\b|\bG\b|\bPG\b|\bPG\-13\b|\bR\b|\bNC\-17\b$", RegexOptions.IgnoreCase)
|
||||
.When(c => c.Ceritification.IsNotNullOrWhiteSpace())
|
||||
.WithMessage("Not a valid cerification");
|
||||
.WithMessage("Not a valid certification");
|
||||
|
||||
// CSV of numbers
|
||||
RuleFor(c => c.IncludeGenreIds)
|
||||
.Matches(@"^\d+([,]\d+)*$", RegexOptions.IgnoreCase)
|
||||
.Matches(@"^\d+([,|]\d+)*$", RegexOptions.IgnoreCase)
|
||||
.When(c => c.IncludeGenreIds.IsNotNullOrWhiteSpace())
|
||||
.WithMessage("Genre Ids must be comma separated number ids");
|
||||
.WithMessage("Genre Ids must be comma (,) or pipe (|) separated number ids");
|
||||
|
||||
// CSV of numbers
|
||||
RuleFor(c => c.ExcludeGenreIds)
|
||||
.Matches(@"^\d+([,]\d+)*$", RegexOptions.IgnoreCase)
|
||||
.Matches(@"^\d+([,|]\d+)*$", RegexOptions.IgnoreCase)
|
||||
.When(c => c.ExcludeGenreIds.IsNotNullOrWhiteSpace())
|
||||
.WithMessage("Genre Ids must be comma separated number ids");
|
||||
.WithMessage("Genre Ids must be comma (,) or pipe (|) separated number ids");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -99,4 +99,4 @@ namespace NzbDrone.Core.NetImport.TMDb
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,9 @@
|
||||
<Compile Include="Datastore\Migration\123_create_netimport_table.cs" />
|
||||
<Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" />
|
||||
<Compile Include="Datastore\Migration\141_fix_duplicate_alt_titles.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\RequiredIndexerFlagsSpecification.cs" />
|
||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedAlternativeTitles.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\GrabbedReleaseQualitySpecification.cs" />
|
||||
<Compile Include="MediaFiles\Events\MovieFileUpdatedEvent.cs" />
|
||||
<Compile Include="Datastore\Migration\134_add_remux_qualities_for_the_wankers.cs" />
|
||||
<Compile Include="Datastore\Migration\129_add_parsed_movie_info_to_pending_release.cs" />
|
||||
@@ -1392,4 +1394,4 @@
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Organizer
|
||||
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?Title(The)?)\})",
|
||||
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?(Title|Filename)(The)?)\})",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
|
||||
@@ -633,6 +633,15 @@ namespace NzbDrone.Core.Organizer
|
||||
|
||||
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Movie movie, MovieFile movieFile)
|
||||
{
|
||||
if (movieFile?.Quality?.Quality == null)
|
||||
{
|
||||
tokenHandlers["{Quality Full}"] = m => "";
|
||||
tokenHandlers["{Quality Title}"] = m => "";
|
||||
tokenHandlers["{Quality Proper}"] = m => "";
|
||||
tokenHandlers["{Quality Real}"] = m => "";
|
||||
return;
|
||||
}
|
||||
|
||||
var qualityTitle = _qualityDefinitionService.Get(movieFile.Quality.Quality).Title;
|
||||
var qualityProper = GetQualityProper(movie, movieFile.Quality);
|
||||
var qualityReal = GetQualityReal(movie, movieFile.Quality);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ namespace NzbDrone.Core.RootFolders
|
||||
public string Path { get; set; }
|
||||
|
||||
public long? FreeSpace { get; set; }
|
||||
public long? TotalSpace { get; set; }
|
||||
|
||||
public List<UnmappedFolder> UnmappedFolders { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -76,14 +76,15 @@ namespace NzbDrone.Core.RootFolders
|
||||
if (folder.Path.IsPathValid() && _diskProvider.FolderExists(folder.Path))
|
||||
{
|
||||
folder.FreeSpace = _diskProvider.GetAvailableSpace(folder.Path);
|
||||
folder.TotalSpace = _diskProvider.GetTotalSize(folder.Path);
|
||||
folder.UnmappedFolders = GetUnmappedFolders(folder.Path);
|
||||
}
|
||||
}
|
||||
//We don't want an exception to prevent the root folders from loading in the UI, so they can still be deleted
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to get free space and unmapped folders for root folder: " + folder.Path);
|
||||
folder.FreeSpace = 0;
|
||||
_logger.Error(ex, "Unable to get free space and unmapped folders for root folder {0}", folder.Path);
|
||||
folder.UnmappedFolders = new List<UnmappedFolder>();
|
||||
}
|
||||
});
|
||||
@@ -211,8 +212,9 @@ namespace NzbDrone.Core.RootFolders
|
||||
{
|
||||
var rootFolder = _rootFolderRepository.Get(id);
|
||||
rootFolder.FreeSpace = _diskProvider.GetAvailableSpace(rootFolder.Path);
|
||||
rootFolder.TotalSpace = _diskProvider.GetTotalSize(rootFolder.Path);
|
||||
rootFolder.UnmappedFolders = GetUnmappedFolders(rootFolder.Path);
|
||||
return rootFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,13 @@
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_FIXED_STMT/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_USINGS_STMT/@EntryValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">ALWAYS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AllowAlias/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/CanUseGlobalAlias/@EntryValue">False</s:Boolean>
|
||||
@@ -66,7 +70,12 @@
|
||||
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File_003A_003AC_003A_005CDropbox_005CGit_005CNzbDrone_005CNzbDrone_002Esln_002EDotSettings/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File_003A_003AC_003A_005CDropbox_005CGit_005CNzbDrone_005CNzbDrone_002Esln_002EDotSettings/RelativePriority/@EntryValue">2</s:Double>
|
||||
<s:Boolean x:Key="/Default/Environment/MemoryUsageIndicator/IsVisible/@EntryValue">False</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/TextControl/HighlightCurrentLine/@EntryValue">True</s:Boolean>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Debug - Chrome" type="JavascriptDebugType" factoryName="JavaScript Debug" singleton="true" engineId="98ca6316-2f89-46d9-a9e5-fa9e2b0625b3" uri="http://localhost:7878">
|
||||
<mapping url="http://localhost:8989/Wanted" local-file="$PROJECT_DIR$/Wanted" />
|
||||
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
|
||||
<mapping url="http://localhost:8989" local-file="$PROJECT_DIR$" />
|
||||
<mapping url="http://localhost:8989/Wanted" local-file="$PROJECT_DIR$/Wanted" />
|
||||
<mapping url="http://localhost:8989/app.js" local-file="$PROJECT_DIR$/app.js" />
|
||||
<mapping url="http://localhost:8989/Mixins" local-file="$PROJECT_DIR$/Mixins" />
|
||||
<mapping url="http://localhost:8989/Quality" local-file="$PROJECT_DIR$/Quality" />
|
||||
<mapping url="http://localhost:8989/Shared" local-file="$PROJECT_DIR$/Shared" />
|
||||
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
|
||||
<mapping url="http://localhost:8989/Calendar" local-file="$PROJECT_DIR$/Calendar" />
|
||||
<mapping url="http://localhost:8989/Controller.js" local-file="$PROJECT_DIR$/Controller.js" />
|
||||
<mapping url="http://localhost:8989/Series" local-file="$PROJECT_DIR$/Series" />
|
||||
<mapping url="http://localhost:8989/AddSeries" local-file="$PROJECT_DIR$/AddSeries" />
|
||||
<mapping url="http://localhost:8989/Settings" local-file="$PROJECT_DIR$/Settings" />
|
||||
<mapping url="http://localhost:8989/Config.js" local-file="$PROJECT_DIR$/Config.js" />
|
||||
<RunnerSettings RunnerId="JavascriptDebugRunner" />
|
||||
<ConfigurationWrapper RunnerId="JavascriptDebugRunner" />
|
||||
<method />
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<h3>
|
||||
{{#if_eq eventType compare="grabbed"}}Grabbed{{/if_eq}}
|
||||
{{#if_eq eventType compare="downloadFailed"}}Download Failed{{/if_eq}}
|
||||
{{#if_eq eventType compare="downloadFolderImported"}}Episode Imported{{/if_eq}}
|
||||
{{#if_eq eventType compare="episodeFileDeleted"}}Episode File Deleted{{/if_eq}}
|
||||
{{#if_eq eventType compare="downloadFolderImported"}}Movie Imported{{/if_eq}}
|
||||
{{#if_eq eventType compare="episodeFileDeleted"}}Movie File Deleted{{/if_eq}}
|
||||
</h3>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -36,7 +36,7 @@ var Collection = PageableCollection.extend({
|
||||
},
|
||||
|
||||
sortMappings : {
|
||||
series : {
|
||||
movie : {
|
||||
sortValue : function(model, attr, order) {
|
||||
var series = model.get(attr);
|
||||
|
||||
@@ -71,4 +71,4 @@ var Collection = PageableCollection.extend({
|
||||
|
||||
Collection = AsSortedCollection.call(Collection);
|
||||
|
||||
module.exports = Collection;
|
||||
module.exports = Collection;
|
||||
|
||||
@@ -22,9 +22,7 @@ module.exports = Backgrid.Row.extend({
|
||||
},
|
||||
|
||||
_setError : function () {
|
||||
if (this.model.has('series') &&
|
||||
this.model.has('seasonNumber') &&
|
||||
(this.model.has('episodes') && this.model.get('episodes').length > 0)&&
|
||||
if (this.model.has('movie') &&
|
||||
this.model.has('quality')) {
|
||||
this.$el.removeClass('manual-import-error');
|
||||
}
|
||||
@@ -35,7 +33,7 @@ module.exports = Backgrid.Row.extend({
|
||||
},
|
||||
|
||||
_setClasses : function () {
|
||||
this.$el.toggleClass('has-series', this.model.has('series'));
|
||||
this.$el.toggleClass('has-season', this.model.has('seasonNumber'));
|
||||
this.$el.toggleClass('has-movie', this.model.has('movie'));
|
||||
//this.$el.toggleClass('has-season', this.model.has('seasonNumber'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -87,8 +87,8 @@ module.exports = Marionette.Layout.extend({
|
||||
|
||||
_filter : function (term) {
|
||||
this.movieCollection.reset(this.fullMovieCollection.filter(function(model){
|
||||
return model.get("title").toLowerCase().indexOf(term.toLowerCase()) != -1;
|
||||
}).slice(0, 20));
|
||||
return (model.get("title") + " "+model.get("year")+"").toLowerCase().indexOf(term.toLowerCase()) != -1;
|
||||
}).slice(0, 50));
|
||||
|
||||
this._setModelCollection();
|
||||
//this.movieView.render();
|
||||
|
||||
@@ -7,7 +7,7 @@ var EditProfileItemView = require('./EditProfileItemView');
|
||||
var QualitySortableCollectionView = require('./QualitySortableCollectionView');
|
||||
var EditProfileView = require('./EditProfileView');
|
||||
var DeleteView = require('../DeleteProfileView');
|
||||
var SeriesCollection = require('../../../Series/SeriesCollection');
|
||||
var FullMovieCollection = require('../../../Movies/FullMovieCollection');
|
||||
var Config = require('../../../Config');
|
||||
var AsEditModalView = require('../../../Mixins/AsEditModalView');
|
||||
|
||||
@@ -28,7 +28,7 @@ var view = Marionette.Layout.extend({
|
||||
initialize : function(options) {
|
||||
this.profileCollection = options.profileCollection;
|
||||
this.itemsCollection = new Backbone.Collection(_.toArray(this.model.get('items')).reverse());
|
||||
this.listenTo(SeriesCollection, 'all', this._updateDisableStatus);
|
||||
this.listenTo(FullMovieCollection, 'all', this._updateDisableStatus);
|
||||
},
|
||||
|
||||
onRender : function() {
|
||||
@@ -104,14 +104,14 @@ var view = Marionette.Layout.extend({
|
||||
_updateDisableStatus : function() {
|
||||
if (this._isQualityInUse()) {
|
||||
this.ui.deleteButton.addClass('disabled');
|
||||
this.ui.deleteButton.attr('title', 'Can\'t delete a profile that is attached to a series.');
|
||||
this.ui.deleteButton.attr('title', 'Can\'t delete a profile that is attached to a movie.');
|
||||
} else {
|
||||
this.ui.deleteButton.removeClass('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
_isQualityInUse : function() {
|
||||
return SeriesCollection.where({ 'profileId' : this.model.id }).length !== 0;
|
||||
return FullMovieCollection.where({ 'profileId' : this.model.id }).length !== 0;
|
||||
}
|
||||
});
|
||||
module.exports = AsEditModalView.call(view);
|
||||
|
||||
Reference in New Issue
Block a user