mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-18 21:35:51 -04:00
Compare commits
71 Commits
v2.0.0.492
...
v2.0.0.505
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf7b8455d4 | ||
|
|
df3c6ed572 | ||
|
|
e6c01be2cb | ||
|
|
2196db9a58 | ||
|
|
f10174da37 | ||
|
|
b48eaa7fd3 | ||
|
|
c34eec160f | ||
|
|
393996fe88 | ||
|
|
1ef08424ff | ||
|
|
20af2c8c0f | ||
|
|
b7e74bd5be | ||
|
|
34ded19be4 | ||
|
|
f53cad822a | ||
|
|
090dd45541 | ||
|
|
e01e822394 | ||
|
|
ea5769fdd6 | ||
|
|
1d2b35fdde | ||
|
|
1d3c536c93 | ||
|
|
e6b8b17b21 | ||
|
|
2a0df7e83e | ||
|
|
12065948ca | ||
|
|
a9e1aee295 | ||
|
|
73cb789f59 | ||
|
|
7345811115 | ||
|
|
22378b28f5 | ||
|
|
961f0d0ad3 | ||
|
|
65187e7d01 | ||
|
|
00c3074216 | ||
|
|
e042388a97 | ||
|
|
2b8ab92ef7 | ||
|
|
7b7f48a0e3 | ||
|
|
714ce2640b | ||
|
|
7c5daa6000 | ||
|
|
ea7d7d0a14 | ||
|
|
8bc55c5305 | ||
|
|
50b01d8d00 | ||
|
|
9c1d275403 | ||
|
|
5372ed5d40 | ||
|
|
6626397350 | ||
|
|
ef8b882258 | ||
|
|
728f553802 | ||
|
|
bc32ad064e | ||
|
|
56825da6b6 | ||
|
|
17ff52ada1 | ||
|
|
bbd38dec29 | ||
|
|
77cdb542b6 | ||
|
|
52ce2c0007 | ||
|
|
58d158a5dc | ||
|
|
de5d120aac | ||
|
|
19a4d3536b | ||
|
|
bea4954de9 | ||
|
|
810701ad52 | ||
|
|
f3bf50e8d7 | ||
|
|
fa34af8f15 | ||
|
|
9a82f45020 | ||
|
|
7d21585f50 | ||
|
|
51d08fd8e8 | ||
|
|
078b53dc13 | ||
|
|
b8b0f05920 | ||
|
|
b8001943b4 | ||
|
|
c70740e3b6 | ||
|
|
35f911286f | ||
|
|
650f01176c | ||
|
|
2246dfab05 | ||
|
|
6bfb790eb8 | ||
|
|
0e85e39815 | ||
|
|
9471343533 | ||
|
|
2d1d1c8a99 | ||
|
|
7e5e136930 | ||
|
|
c659ba1c10 | ||
|
|
caf7a8c69e |
39
.github/ISSUE_TEMPLATE.md
vendored
39
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,5 +1,40 @@
|
|||||||
|
<!--
|
||||||
|
Before opening a new issue, please ensure:
|
||||||
|
- You use the forums for support/questions
|
||||||
|
- You search for existing bugs/feature requests
|
||||||
|
- Remove extraneous template details
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Support / Questions
|
||||||
|
|
||||||
|
Please use https://forums.sonarr.tv/ for support. Support requests or questions will be redirected to the forums and the issue will be closed.
|
||||||
|
|
||||||
Provide a description of the feature request or bug, the more details the better.
|
<!--
|
||||||
Please use https://forums.sonarr.tv/ for support or other questions. (When in doubt, use the forums)
|
Remove if not opening a bug report
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Bug Report
|
||||||
|
|
||||||
|
### System Information/Logs
|
||||||
|
|
||||||
|
**Sonarr Version:**
|
||||||
|
|
||||||
|
**Operating System:**
|
||||||
|
|
||||||
|
**.net Framework (Windows) or mono (macOS/Linux) Version:**
|
||||||
|
|
||||||
|
**Link to Log Files (debug or trace):**
|
||||||
|
|
||||||
|
**Browser (for UI bugs):**
|
||||||
|
|
||||||
|
### Additional Information
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Remove if not opening a feature request
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Feature Request
|
||||||
|
|
||||||
|
### What problem are you looking to solve?
|
||||||
|
|
||||||
|
### Other Information
|
||||||
|
|||||||
7
.github/SUPPORT.md
vendored
Normal file
7
.github/SUPPORT.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Support
|
||||||
|
|
||||||
|
There are a number of frequently asked questions that have been answered in our [FAQ](https://github.com/Sonarr/Sonarr/wiki/FAQ)
|
||||||
|
|
||||||
|
The [wiki](https://github.com/Sonarr/Sonarr/wiki) contains other information and guides
|
||||||
|
|
||||||
|
If you have a support question, please use the [support forums](https://forums.sonarr.tv/).
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#SET BUILD_NUMBER=1
|
REM SET BUILD_NUMBER=1
|
||||||
#SET branch=develop
|
REM SET branch=develop
|
||||||
inno\ISCC.exe nzbdrone.iss
|
inno\ISCC.exe nzbdrone.iss
|
||||||
@@ -40,8 +40,11 @@ VersionInfoVersion={#BuildNumber}
|
|||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
[Tasks]
|
[Tasks]
|
||||||
;Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"
|
||||||
Name: "windowsService"; Description: "Install as a Windows Service"
|
Name: "windowsService"; Description: "Install Windows Service (Starts when the computer starts)"; GroupDescription: "Start automatically"; Flags: exclusive
|
||||||
|
Name: "startupShortcut"; Description: "Create shortcut in Startup folder (Starts when you log into Windows)"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
|
||||||
|
Name: "none"; Description: "Do not start automatically"; GroupDescription: "Start automatically"; Flags: exclusive unchecked
|
||||||
|
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
Source: "..\_output\NzbDrone.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "..\_output\NzbDrone.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
@@ -51,10 +54,13 @@ Source: "..\_output\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs cr
|
|||||||
[Icons]
|
[Icons]
|
||||||
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"
|
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"
|
||||||
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"
|
Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppExeName}"; Parameters: "/icon"
|
||||||
|
Name: "{userstartup}\{#AppName}"; Filename: "{app}\NzbDrone.exe"; WorkingDir: "{app}"; Tasks: startupShortcut
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{app}\nzbdrone.console.exe"; Parameters: "/u"; Flags: waituntilterminated;
|
Filename: "{app}\nzbdrone.console.exe"; Parameters: "/u"; Flags: runhidden waituntilterminated;
|
||||||
Filename: "{app}\nzbdrone.console.exe"; Parameters: "/i"; Flags: waituntilterminated; Tasks: windowsService
|
Filename: "{app}\nzbdrone.console.exe"; Parameters: "/i"; Flags: runhidden waituntilterminated; Tasks: windowsService
|
||||||
|
Filename: "{app}\NzbDrone.exe"; Description: "Open Sonarr"; Flags: postinstall skipifsilent nowait; Tasks: windowsService;
|
||||||
|
Filename: "{app}\NzbDrone.exe"; Description: "Start Sonarr"; Flags: postinstall skipifsilent nowait; Tasks: startupShortcut none;
|
||||||
|
|
||||||
[UninstallRun]
|
[UninstallRun]
|
||||||
Filename: "{app}\nzbdrone.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
|
Filename: "{app}\nzbdrone.console.exe"; Parameters: "/u"; Flags: waituntilterminated skipifdoesntexist
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -48,8 +48,8 @@
|
|||||||
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Moq, Version=4.2.1510.2205, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
||||||
<package id="Moq" version="4.0.10827" />
|
<package id="Moq" version="4.0.10827" targetFramework="net40" />
|
||||||
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
|
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
|
||||||
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using Nancy;
|
using Nancy;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Ical.Net;
|
using Ical.Net;
|
||||||
using Ical.Net.DataTypes;
|
using Ical.Net.DataTypes;
|
||||||
|
using Ical.Net.General;
|
||||||
using Ical.Net.Interfaces.Serialization;
|
using Ical.Net.Interfaces.Serialization;
|
||||||
using Ical.Net.Serialization;
|
using Ical.Net.Serialization;
|
||||||
using Ical.Net.Serialization.iCalendar.Factory;
|
using Ical.Net.Serialization.iCalendar.Factory;
|
||||||
@@ -92,7 +93,9 @@ namespace NzbDrone.Api.Calendar
|
|||||||
ProductId = "-//sonarr.tv//Sonarr//EN"
|
ProductId = "-//sonarr.tv//Sonarr//EN"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var calendarName = "Sonarr TV Schedule";
|
||||||
|
calendar.AddProperty(new CalendarProperty("NAME", calendarName));
|
||||||
|
calendar.AddProperty(new CalendarProperty("X-WR-CALNAME", calendarName));
|
||||||
|
|
||||||
foreach (var episode in episodes.OrderBy(v => v.AirDateUtc.Value))
|
foreach (var episode in episodes.OrderBy(v => v.AirDateUtc.Value))
|
||||||
{
|
{
|
||||||
@@ -114,7 +117,7 @@ namespace NzbDrone.Api.Calendar
|
|||||||
|
|
||||||
if (asAllDay)
|
if (asAllDay)
|
||||||
{
|
{
|
||||||
occurrence.Start = new CalDateTime(episode.AirDateUtc.Value) { HasTime = false };
|
occurrence.Start = new CalDateTime(episode.AirDateUtc.Value.ToLocalTime()) { HasTime = false };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Nancy;
|
using Nancy;
|
||||||
@@ -21,10 +21,7 @@ namespace NzbDrone.Api.Frontend.Mappers
|
|||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
if (!RuntimeInfo.IsProduction)
|
_caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase;
|
||||||
{
|
|
||||||
_caseSensitive = StringComparison.OrdinalIgnoreCase;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract string Map(string resourceUrl);
|
public abstract string Map(string resourceUrl);
|
||||||
@@ -50,6 +47,5 @@ namespace NzbDrone.Api.Frontend.Mappers
|
|||||||
{
|
{
|
||||||
return File.OpenRead(filePath);
|
return File.OpenRead(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Nancy;
|
using Nancy;
|
||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
using NzbDrone.Api.Extensions;
|
using NzbDrone.Api.Extensions;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
using NzbDrone.Api.Series;
|
using NzbDrone.Api.Series;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
@@ -25,6 +28,7 @@ namespace NzbDrone.Api.History
|
|||||||
_failedDownloadService = failedDownloadService;
|
_failedDownloadService = failedDownloadService;
|
||||||
GetResourcePaged = GetHistory;
|
GetResourcePaged = GetHistory;
|
||||||
|
|
||||||
|
Get["/since"] = x => GetHistorySince();
|
||||||
Post["/failed"] = x => MarkAsFailed();
|
Post["/failed"] = x => MarkAsFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +68,27 @@ namespace NzbDrone.Api.History
|
|||||||
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);
|
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<HistoryResource> GetHistorySince()
|
||||||
|
{
|
||||||
|
var queryDate = Request.Query.Date;
|
||||||
|
var queryEventType = Request.Query.EventType;
|
||||||
|
|
||||||
|
if (!queryDate.HasValue)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("date is missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime date = DateTime.Parse(queryDate.Value);
|
||||||
|
HistoryEventType? eventType = null;
|
||||||
|
|
||||||
|
if (queryEventType.HasValue)
|
||||||
|
{
|
||||||
|
eventType = (HistoryEventType)Convert.ToInt32(queryEventType.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _historyService.Since(date, eventType).Select(MapToResource).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
private Response MarkAsFailed()
|
private Response MarkAsFailed()
|
||||||
{
|
{
|
||||||
var id = (int)Request.Form.Id;
|
var id = (int)Request.Form.Id;
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ namespace NzbDrone.Api
|
|||||||
RegisterPipelines(pipelines);
|
RegisterPipelines(pipelines);
|
||||||
|
|
||||||
container.Resolve<DatabaseTarget>().Register();
|
container.Resolve<DatabaseTarget>().Register();
|
||||||
container.Resolve<IEventAggregator>().PublishEvent(new ApplicationStartedEvent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterPipelines(IPipelines pipelines)
|
private void RegisterPipelines(IPipelines pipelines)
|
||||||
@@ -56,4 +55,4 @@ namespace NzbDrone.Api
|
|||||||
|
|
||||||
protected override byte[] FavIcon => null;
|
protected override byte[] FavIcon => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NodaTime, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4226afe0d9b296d1, processorArchitecture=MSIL">
|
<Reference Include="NodaTime, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4226afe0d9b296d1, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Ical.Net.2.2.32\lib\net40\NodaTime.dll</HintPath>
|
<HintPath>..\packages\Ical.Net.2.2.32\lib\net40\NodaTime.dll</HintPath>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
using NzbDrone.Api.Series;
|
using NzbDrone.Api.Series;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Parse
|
namespace NzbDrone.Api.Parse
|
||||||
@@ -18,7 +19,8 @@ namespace NzbDrone.Api.Parse
|
|||||||
private ParseResource Parse()
|
private ParseResource Parse()
|
||||||
{
|
{
|
||||||
var title = Request.Query.Title.Value as string;
|
var title = Request.Query.Title.Value as string;
|
||||||
var parsedEpisodeInfo = Parser.ParseTitle(title);
|
var path = Request.Query.Path.Value as string;
|
||||||
|
var parsedEpisodeInfo = path.IsNotNullOrWhiteSpace() ? Parser.ParsePath(path) : Parser.ParseTitle(title);
|
||||||
|
|
||||||
if (parsedEpisodeInfo == null)
|
if (parsedEpisodeInfo == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ namespace NzbDrone.Api.System.Backup
|
|||||||
|
|
||||||
return backups.Select(b => new BackupResource
|
return backups.Select(b => new BackupResource
|
||||||
{
|
{
|
||||||
Id = b.Path.GetHashCode(),
|
Id = b.Name.GetHashCode(),
|
||||||
Name = Path.GetFileName(b.Path),
|
Name = b.Name,
|
||||||
Path = b.Path,
|
Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}",
|
||||||
Type = b.Type,
|
Type = b.Type,
|
||||||
Time = b.Time
|
Time = b.Time
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
<package id="Nancy.Authentication.Basic" version="1.4.1" targetFramework="net40" />
|
<package id="Nancy.Authentication.Basic" version="1.4.1" targetFramework="net40" />
|
||||||
<package id="Nancy.Authentication.Forms" version="1.4.1" targetFramework="net40" />
|
<package id="Nancy.Authentication.Forms" version="1.4.1" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -47,8 +47,12 @@
|
|||||||
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
||||||
@@ -58,9 +62,6 @@
|
|||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="Moq">
|
|
||||||
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ContainerFixture.cs" />
|
<Compile Include="ContainerFixture.cs" />
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
||||||
<package id="Moq" version="4.0.10827" />
|
<package id="Moq" version="4.0.10827" targetFramework="net40" />
|
||||||
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
|
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
||||||
<package id="Selenium.Support" version="3.2.0" targetFramework="net40" />
|
<package id="Selenium.Support" version="3.2.0" targetFramework="net40" />
|
||||||
<package id="Selenium.WebDriver" version="3.2.0" targetFramework="net40" />
|
<package id="Selenium.WebDriver" version="3.2.0" targetFramework="net40" />
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Moq;
|
using Moq;
|
||||||
@@ -238,7 +238,7 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||||||
|
|
||||||
WithExistingFile(_targetPath);
|
WithExistingFile(_targetPath);
|
||||||
|
|
||||||
Assert.Throws<IOException>(() => Subject.TransferFile(_sourcePath, _targetPath, TransferMode.Move, false));
|
Assert.Throws<DestinationAlreadyExistsException>(() => Subject.TransferFile(_sourcePath, _targetPath, TransferMode.Move, false));
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Verify(v => v.DeleteFile(_targetPath), Times.Never());
|
.Verify(v => v.DeleteFile(_targetPath), Times.Never());
|
||||||
|
|||||||
@@ -139,11 +139,26 @@ namespace NzbDrone.Common.Test.Http
|
|||||||
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
||||||
request.AllowAutoRedirect = true;
|
request.AllowAutoRedirect = true;
|
||||||
|
|
||||||
Subject.Get(request);
|
var response = Subject.Get(request);
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
ExceptionVerification.ExpectedErrors(0);
|
ExceptionVerification.ExpectedErrors(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_follow_redirects()
|
||||||
|
{
|
||||||
|
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
||||||
|
request.AllowAutoRedirect = false;
|
||||||
|
|
||||||
|
var response = Subject.Get(request);
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.Found);
|
||||||
|
|
||||||
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_follow_redirects_to_https()
|
public void should_follow_redirects_to_https()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
|
|||||||
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=sonarr&api=mySecret&eng=1")]
|
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=sonarr&api=mySecret&eng=1")]
|
||||||
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
|
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
|
||||||
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
|
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
|
||||||
|
[TestCase(@"http://127.0.0.1:9117/dl/indexername?jackett_apikey=flwjiefewklfjacketmySecretsdfldskjfsdlk&path=we0re9f0sdfbase64sfdkfjsdlfjk&file=The+Torrent+File+Name.torrent")]
|
||||||
// NzbGet
|
// NzbGet
|
||||||
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
|
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
|
||||||
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]
|
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]
|
||||||
|
|||||||
@@ -43,8 +43,12 @@
|
|||||||
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
||||||
@@ -57,9 +61,6 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="Moq">
|
|
||||||
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="CacheTests\CachedDictionaryFixture.cs" />
|
<Compile Include="CacheTests\CachedDictionaryFixture.cs" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
|
||||||
<package id="Moq" version="4.0.10827" />
|
<package id="Moq" version="4.0.10827" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
@@ -24,6 +24,8 @@ namespace NzbDrone.Common
|
|||||||
Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
|
Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
|
||||||
Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
|
Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
|
||||||
Console.WriteLine(" /{0} Don't open Sonarr in a browser", StartupContext.NO_BROWSER);
|
Console.WriteLine(" /{0} Don't open Sonarr in a browser", StartupContext.NO_BROWSER);
|
||||||
|
Console.WriteLine(" /{0} Start Sonarr terminating any other instances", StartupContext.TERMINATE);
|
||||||
|
Console.WriteLine(" /{0}=path Path to use as the AppData location (stores database, config, logs, etc)", StartupContext.APPDATA);
|
||||||
Console.WriteLine(" <No Arguments> Run application in console mode.");
|
Console.WriteLine(" <No Arguments> Run application in console mode.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,4 +39,4 @@ namespace NzbDrone.Common
|
|||||||
Console.WriteLine("Can't find service ({0})", ServiceProvider.NZBDRONE_SERVICE_NAME);
|
Console.WriteLine("Can't find service ({0})", ServiceProvider.NZBDRONE_SERVICE_NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common.Disk
|
||||||
|
{
|
||||||
|
public class DestinationAlreadyExistsException : IOException
|
||||||
|
{
|
||||||
|
public DestinationAlreadyExistsException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DestinationAlreadyExistsException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DestinationAlreadyExistsException(string message, int hresult) : base(message, hresult)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DestinationAlreadyExistsException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DestinationAlreadyExistsException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnsureThat;
|
using NzbDrone.Common.EnsureThat;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
namespace NzbDrone.Common.Disk
|
namespace NzbDrone.Common.Disk
|
||||||
@@ -340,7 +341,7 @@ namespace NzbDrone.Common.Disk
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new IOException(string.Format("Destination already exists. [{0}] to [{1}]", sourcePath, targetPath));
|
throw new DestinationAlreadyExistsException($"Destination {targetPath} already exists.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace NzbDrone.Common.Disk
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (VolumeLabel.IsNullOrWhiteSpace())
|
if (VolumeLabel.IsNullOrWhiteSpace() || VolumeLabel.StartsWith("UUID=") || Name == VolumeLabel)
|
||||||
{
|
{
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace NzbDrone.Common.Exceptions
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common.Disk
|
||||||
{
|
{
|
||||||
public class NotParentException : NzbDroneException
|
public class NotParentException : NzbDroneException
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace NzbDrone.Common.EnvironmentInfo
|
namespace NzbDrone.Common.EnvironmentInfo
|
||||||
{
|
{
|
||||||
public interface IRuntimeInfo
|
public interface IRuntimeInfo
|
||||||
@@ -7,8 +5,9 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
bool IsUserInteractive { get; }
|
bool IsUserInteractive { get; }
|
||||||
bool IsAdmin { get; }
|
bool IsAdmin { get; }
|
||||||
bool IsWindowsService { get; }
|
bool IsWindowsService { get; }
|
||||||
|
bool IsWindowsTray { get; }
|
||||||
bool IsExiting { get; set; }
|
bool IsExiting { get; set; }
|
||||||
bool RestartPending { get; set; }
|
bool RestartPending { get; set; }
|
||||||
string ExecutingApplication { get; }
|
string ExecutingApplication { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.Processes;
|
||||||
|
|
||||||
namespace NzbDrone.Common.EnvironmentInfo
|
namespace NzbDrone.Common.EnvironmentInfo
|
||||||
{
|
{
|
||||||
@@ -27,6 +28,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
ExecutingApplication = entry.Location;
|
ExecutingApplication = entry.Location;
|
||||||
|
IsWindowsTray = entry.ManifestModule.Name == $"{ProcessProvider.NZB_DRONE_PROCESS_NAME}.exe";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,5 +104,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsWindowsTray { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -59,7 +59,7 @@ namespace NzbDrone.Common.Extensions
|
|||||||
{
|
{
|
||||||
if (!parentPath.IsParentPath(childPath))
|
if (!parentPath.IsParentPath(childPath))
|
||||||
{
|
{
|
||||||
throw new Exceptions.NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
throw new NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
||||||
|
|||||||
@@ -52,36 +52,33 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public HttpResponse Execute(HttpRequest request)
|
public HttpResponse Execute(HttpRequest request)
|
||||||
{
|
{
|
||||||
var autoRedirectCount = 0;
|
|
||||||
var autoRedirectChain = new List<string>();
|
|
||||||
autoRedirectChain.Add(request.Url.ToString());
|
|
||||||
|
|
||||||
var response = ExecuteRequest(request);
|
var response = ExecuteRequest(request);
|
||||||
|
|
||||||
while (response.StatusCode == HttpStatusCode.Moved ||
|
if (request.AllowAutoRedirect && response.HasHttpRedirect)
|
||||||
response.StatusCode == HttpStatusCode.MovedPermanently ||
|
|
||||||
response.StatusCode == HttpStatusCode.Found)
|
|
||||||
{
|
{
|
||||||
if (request.AllowAutoRedirect)
|
var autoRedirectChain = new List<string>();
|
||||||
|
autoRedirectChain.Add(request.Url.ToString());
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
request.Url += new HttpUri(response.Headers.GetSingleValue("Location"));
|
request.Url += new HttpUri(response.Headers.GetSingleValue("Location"));
|
||||||
autoRedirectChain.Add(request.Url.ToString());
|
autoRedirectChain.Add(request.Url.ToString());
|
||||||
|
|
||||||
_logger.Trace("Redirected to {0}", request.Url);
|
_logger.Trace("Redirected to {0}", request.Url);
|
||||||
|
|
||||||
autoRedirectCount++;
|
if (autoRedirectChain.Count > 3)
|
||||||
if (autoRedirectCount > 3)
|
|
||||||
{
|
{
|
||||||
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
|
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
|
||||||
}
|
}
|
||||||
|
|
||||||
response = ExecuteRequest(request);
|
response = ExecuteRequest(request);
|
||||||
}
|
}
|
||||||
else if (!RuntimeInfo.IsProduction)
|
while (response.HasHttpRedirect);
|
||||||
{
|
}
|
||||||
_logger.Error("Server requested a redirect to [{0}]. Update the request URL to avoid this redirect.", response.Headers["Location"]);
|
|
||||||
break;
|
if (response.HasHttpRedirect && !RuntimeInfo.IsProduction)
|
||||||
}
|
{
|
||||||
|
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request.SuppressHttpError && response.HasHttpError)
|
if (!request.SuppressHttpError && response.HasHttpError)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
private string _content;
|
private string _content;
|
||||||
|
|
||||||
public string Content
|
public string Content
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -51,6 +51,10 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public bool HasHttpError => (int)StatusCode >= 400;
|
public bool HasHttpError => (int)StatusCode >= 400;
|
||||||
|
|
||||||
|
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
|
||||||
|
StatusCode == HttpStatusCode.MovedPermanently ||
|
||||||
|
StatusCode == HttpStatusCode.Found;
|
||||||
|
|
||||||
public Dictionary<string, string> GetCookies()
|
public Dictionary<string, string> GetCookies()
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, string>();
|
var result = new Dictionary<string, string>();
|
||||||
@@ -95,4 +99,4 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public T Resource { get; private set; }
|
public T Resource { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
{
|
{
|
||||||
public class CleanseLogMessage
|
public class CleanseLogMessage
|
||||||
{
|
{
|
||||||
private static readonly Regex[] CleansingRules = new[]
|
private static readonly Regex[] CleansingRules = new[]
|
||||||
{
|
{
|
||||||
// Url
|
// Url
|
||||||
new Regex(@"(?<=\?|&)(apikey|token|passkey|auth|authkey|user|uid|api)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"(?<=\?|&)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Org.Mentalis, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Org.Mentalis, Version=1.0.0.1, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DotNet4.SocksProxy.1.3.4.0\lib\net40\Org.Mentalis.dll</HintPath>
|
<HintPath>..\packages\DotNet4.SocksProxy.1.3.4.0\lib\net40\Org.Mentalis.dll</HintPath>
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
<Compile Include="EnvironmentInfo\IOsVersionAdapter.cs" />
|
<Compile Include="EnvironmentInfo\IOsVersionAdapter.cs" />
|
||||||
<Compile Include="EnvironmentInfo\IPlatformInfo.cs" />
|
<Compile Include="EnvironmentInfo\IPlatformInfo.cs" />
|
||||||
<Compile Include="EnvironmentInfo\OsVersionModel.cs" />
|
<Compile Include="EnvironmentInfo\OsVersionModel.cs" />
|
||||||
|
<Compile Include="Disk\DestinationAlreadyExistsException.cs" />
|
||||||
<Compile Include="Exceptions\SonarrStartupException.cs" />
|
<Compile Include="Exceptions\SonarrStartupException.cs" />
|
||||||
<Compile Include="Extensions\DictionaryExtensions.cs" />
|
<Compile Include="Extensions\DictionaryExtensions.cs" />
|
||||||
<Compile Include="Disk\OsPath.cs" />
|
<Compile Include="Disk\OsPath.cs" />
|
||||||
@@ -125,7 +126,7 @@
|
|||||||
<Compile Include="EnvironmentInfo\IRuntimeInfo.cs" />
|
<Compile Include="EnvironmentInfo\IRuntimeInfo.cs" />
|
||||||
<Compile Include="EnvironmentInfo\RuntimeInfo.cs" />
|
<Compile Include="EnvironmentInfo\RuntimeInfo.cs" />
|
||||||
<Compile Include="EnvironmentInfo\StartupContext.cs" />
|
<Compile Include="EnvironmentInfo\StartupContext.cs" />
|
||||||
<Compile Include="Exceptions\NotParentException.cs" />
|
<Compile Include="Disk\NotParentException.cs" />
|
||||||
<Compile Include="Exceptions\NzbDroneException.cs" />
|
<Compile Include="Exceptions\NzbDroneException.cs" />
|
||||||
<Compile Include="Expansive\CircularReferenceException.cs" />
|
<Compile Include="Expansive\CircularReferenceException.cs" />
|
||||||
<Compile Include="Expansive\Expansive.cs" />
|
<Compile Include="Expansive\Expansive.cs" />
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
<package id="DotNet4.SocksProxy" version="1.3.4.0" targetFramework="net40" />
|
<package id="DotNet4.SocksProxy" version="1.3.4.0" targetFramework="net40" />
|
||||||
<package id="ICSharpCode.SharpZipLib.Patched" version="0.86.5" targetFramework="net40" />
|
<package id="ICSharpCode.SharpZipLib.Patched" version="0.86.5" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
<package id="SharpRaven" version="2.2.0" targetFramework="net40" />
|
<package id="SharpRaven" version="2.2.0" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -57,7 +57,7 @@ namespace NzbDrone.Console
|
|||||||
|
|
||||||
private static void Exit(ExitCodes exitCode)
|
private static void Exit(ExitCodes exitCode)
|
||||||
{
|
{
|
||||||
LogManager.Flush();
|
LogManager.Shutdown();
|
||||||
|
|
||||||
if (exitCode != ExitCodes.Normal)
|
if (exitCode != ExitCodes.Normal)
|
||||||
{
|
{
|
||||||
@@ -80,8 +80,6 @@ namespace NzbDrone.Console
|
|||||||
System.Console.ReadLine();
|
System.Console.ReadLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Need this to terminate on mono (thanks nlog)
|
|
||||||
LogManager.Configuration = null;
|
|
||||||
Environment.Exit((int)exitCode);
|
Environment.Exit((int)exitCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net40" />
|
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net40" />
|
||||||
<package id="Microsoft.Owin.Hosting" version="2.1.0" targetFramework="net40" />
|
<package id="Microsoft.Owin.Hosting" version="2.1.0" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
<package id="Owin" version="1.0" targetFramework="net40" />
|
<package id="Owin" version="1.0" targetFramework="net40" />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -108,7 +108,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.SceneNumbering
|
|||||||
.Verify(v => v.GetSceneTvdbMappings(10), Times.Never());
|
.Verify(v => v.GetSceneTvdbMappings(10), Times.Never());
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -119,7 +119,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.SceneNumbering
|
|||||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.UseSceneNumbering == true)), Times.Once());
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.UseSceneNumbering == true), It.IsAny<bool>()), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -130,7 +130,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.SceneNumbering
|
|||||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Once());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -143,7 +143,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.SceneNumbering
|
|||||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Never());
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ namespace NzbDrone.Core.Test.DataAugmentation.SceneNumbering
|
|||||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Never());
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,27 +49,27 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||||||
{
|
{
|
||||||
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
|
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
|
||||||
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
|
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
|
||||||
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_true_if_all_episodes_have_aired()
|
public void should_return_true_if_all_episodes_have_aired()
|
||||||
{
|
{
|
||||||
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_false_if_one_episode_has_not_aired()
|
public void should_return_false_if_one_episode_has_not_aired()
|
||||||
{
|
{
|
||||||
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
|
_remoteEpisode.Episodes.Last().AirDateUtc = DateTime.UtcNow.AddDays(+2);
|
||||||
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_false_if_an_episode_does_not_have_an_air_date()
|
public void should_return_false_if_an_episode_does_not_have_an_air_date()
|
||||||
{
|
{
|
||||||
_remoteEpisode.Episodes.Last().AirDateUtc = null;
|
_remoteEpisode.Episodes.Last().AirDateUtc = null;
|
||||||
Mocker.Resolve<FullSeasonSpecification>().IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,5 +130,26 @@ namespace NzbDrone.Core.Test.DiskSpace
|
|||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Never());
|
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("/boot")]
|
||||||
|
[TestCase("/var/lib/rancher")]
|
||||||
|
[TestCase("/var/lib/rancher/volumes")]
|
||||||
|
[TestCase("/var/lib/kubelet")]
|
||||||
|
[TestCase("/var/lib/docker")]
|
||||||
|
[TestCase("/some/place/docker/aufs")]
|
||||||
|
public void should_not_check_diskspace_for_irrelevant_mounts(string path)
|
||||||
|
{
|
||||||
|
var mount = new Mock<IMount>();
|
||||||
|
mount.SetupGet(v => v.RootDirectory).Returns(path);
|
||||||
|
mount.SetupGet(v => v.DriveType).Returns(System.IO.DriveType.Fixed);
|
||||||
|
|
||||||
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
.Setup(v => v.GetMounts())
|
||||||
|
.Returns(new List<IMount> { mount.Object });
|
||||||
|
|
||||||
|
var freeSpace = Subject.GetFreeSpace();
|
||||||
|
|
||||||
|
freeSpace.Should().BeEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using NzbDrone.Core.DecisionEngine;
|
|||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.Clients;
|
using NzbDrone.Core.Download.Clients;
|
||||||
using NzbDrone.Core.Download.Pending;
|
using NzbDrone.Core.Download.Pending;
|
||||||
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Profiles;
|
using NzbDrone.Core.Profiles;
|
||||||
@@ -178,7 +179,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_an_empty_list_when_none_are_appproved()
|
public void should_return_an_empty_list_when_none_are_approved()
|
||||||
{
|
{
|
||||||
var decisions = new List<DownloadDecision>();
|
var decisions = new List<DownloadDecision>();
|
||||||
decisions.Add(new DownloadDecision(null, new Rejection("Failure!")));
|
decisions.Add(new DownloadDecision(null, new Rejection("Failure!")));
|
||||||
@@ -263,5 +264,26 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||||||
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteEpisode>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet)), Times.Once());
|
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteEpisode>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet)), Times.Once());
|
||||||
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteEpisode>(r => r.Release.DownloadProtocol == DownloadProtocol.Torrent)), Times.Once());
|
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteEpisode>(r => r.Release.DownloadProtocol == DownloadProtocol.Torrent)), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_add_to_rejected_if_release_unavailable_on_indexer()
|
||||||
|
{
|
||||||
|
var episodes = new List<Episode> { GetEpisode(1) };
|
||||||
|
var remoteEpisode = GetRemoteEpisode(episodes, new QualityModel(Quality.HDTV720p));
|
||||||
|
|
||||||
|
var decisions = new List<DownloadDecision>();
|
||||||
|
decisions.Add(new DownloadDecision(remoteEpisode));
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadService>()
|
||||||
|
.Setup(s => s.DownloadReport(It.IsAny<RemoteEpisode>()))
|
||||||
|
.Throws(new ReleaseUnavailableException(remoteEpisode.Release, "That 404 Error is not just a Quirk"));
|
||||||
|
|
||||||
|
var result = Subject.ProcessDecisions(decisions);
|
||||||
|
|
||||||
|
result.Grabbed.Should().BeEmpty();
|
||||||
|
result.Rejected.Should().NotBeEmpty();
|
||||||
|
|
||||||
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
{
|
{
|
||||||
private RemoteEpisode _parseResult;
|
private RemoteEpisode _parseResult;
|
||||||
private List<IDownloadClient> _downloadClients;
|
private List<IDownloadClient> _downloadClients;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
@@ -82,7 +83,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
{
|
{
|
||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
||||||
|
|
||||||
Subject.DownloadReport(_parseResult);
|
Subject.DownloadReport(_parseResult);
|
||||||
|
|
||||||
VerifyEventPublished<EpisodeGrabbedEvent>();
|
VerifyEventPublished<EpisodeGrabbedEvent>();
|
||||||
@@ -93,7 +94,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
{
|
{
|
||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
||||||
|
|
||||||
Subject.DownloadReport(_parseResult);
|
Subject.DownloadReport(_parseResult);
|
||||||
|
|
||||||
mock.Verify(s => s.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
mock.Verify(s => s.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
||||||
@@ -117,7 +118,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
||||||
.Callback<RemoteEpisode>(v => {
|
.Callback<RemoteEpisode>(v => {
|
||||||
throw new ReleaseDownloadException(v.Release, "Error", new WebException());
|
throw new ReleaseDownloadException(v.Release, "Error", new WebException());
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
||||||
@@ -136,7 +137,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
||||||
.Callback<RemoteEpisode>(v => {
|
.Callback<RemoteEpisode>(v => {
|
||||||
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
|
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
||||||
@@ -180,14 +181,42 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_attempt_download_if_client_isnt_configure()
|
public void Download_report_should_not_trigger_indexer_backoff_on_indexer_404_error()
|
||||||
{
|
{
|
||||||
Subject.DownloadReport(_parseResult);
|
var mock = WithUsenetClient();
|
||||||
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
||||||
|
.Callback<RemoteEpisode>(v => {
|
||||||
|
throw new ReleaseUnavailableException(v.Release, "Error", new WebException());
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Throws<ReleaseUnavailableException>(() => Subject.DownloadReport(_parseResult));
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusService>()
|
||||||
|
.Verify(v => v.RecordFailure(It.IsAny<int>(), It.IsAny<TimeSpan>()), Times.Never());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_attempt_download_if_client_isnt_configured()
|
||||||
|
{
|
||||||
|
Assert.Throws<DownloadClientUnavailableException>(() => Subject.DownloadReport(_parseResult));
|
||||||
|
|
||||||
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||||
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
||||||
|
}
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
[Test]
|
||||||
|
public void should_not_attempt_download_if_client_is_disabled()
|
||||||
|
{
|
||||||
|
WithUsenetClient();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusService>()
|
||||||
|
.Setup(v => v.IsDisabled(It.IsAny<int>()))
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
Assert.Throws<DownloadClientUnavailableException>(() => Subject.DownloadReport(_parseResult));
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||||
|
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Moq;
|
using Moq;
|
||||||
@@ -26,6 +27,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
private ReleaseInfo _release;
|
private ReleaseInfo _release;
|
||||||
private ParsedEpisodeInfo _parsedEpisodeInfo;
|
private ParsedEpisodeInfo _parsedEpisodeInfo;
|
||||||
private RemoteEpisode _remoteEpisode;
|
private RemoteEpisode _remoteEpisode;
|
||||||
|
private List<PendingRelease> _heldReleases;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@@ -60,17 +62,27 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
_remoteEpisode.Series = _series;
|
_remoteEpisode.Series = _series;
|
||||||
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo;
|
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo;
|
||||||
_remoteEpisode.Release = _release;
|
_remoteEpisode.Release = _release;
|
||||||
|
|
||||||
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary));
|
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary));
|
||||||
|
|
||||||
|
_heldReleases = new List<PendingRelease>();
|
||||||
|
|
||||||
Mocker.GetMock<IPendingReleaseRepository>()
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
.Setup(s => s.All())
|
.Setup(s => s.All())
|
||||||
.Returns(new List<PendingRelease>());
|
.Returns(_heldReleases);
|
||||||
|
|
||||||
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
|
.Setup(s => s.AllBySeriesId(It.IsAny<int>()))
|
||||||
|
.Returns<int>(i => _heldReleases.Where(v => v.SeriesId == i).ToList());
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
||||||
.Returns(_series);
|
.Returns(_series);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Setup(s => s.GetSeries(It.IsAny<IEnumerable<int>>()))
|
||||||
|
.Returns(new List<Series> { _series });
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null))
|
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null))
|
||||||
.Returns(new List<Episode> {_episode});
|
.Returns(new List<Episode> {_episode});
|
||||||
@@ -80,7 +92,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.Returns((List<DownloadDecision> d) => d);
|
.Returns((List<DownloadDecision> d) => d);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenHeldRelease(string title, string indexer, DateTime publishDate)
|
private void GivenHeldRelease(string title, string indexer, DateTime publishDate, PendingReleaseReason reason = PendingReleaseReason.Delay)
|
||||||
{
|
{
|
||||||
var release = _release.JsonClone();
|
var release = _release.JsonClone();
|
||||||
release.Indexer = indexer;
|
release.Indexer = indexer;
|
||||||
@@ -92,11 +104,10 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.With(h => h.SeriesId = _series.Id)
|
.With(h => h.SeriesId = _series.Id)
|
||||||
.With(h => h.Title = title)
|
.With(h => h.Title = title)
|
||||||
.With(h => h.Release = release)
|
.With(h => h.Release = release)
|
||||||
|
.With(h => h.Reason = reason)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IPendingReleaseRepository>()
|
_heldReleases.AddRange(heldReleases);
|
||||||
.Setup(s => s.All())
|
|
||||||
.Returns(heldReleases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -117,6 +128,29 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
VerifyNoInsert();
|
VerifyNoInsert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_add_if_it_is_the_same_release_from_the_same_indexer_twice()
|
||||||
|
{
|
||||||
|
GivenHeldRelease(_release.Title, _release.Indexer, _release.PublishDate, PendingReleaseReason.DownloadClientUnavailable);
|
||||||
|
GivenHeldRelease(_release.Title, _release.Indexer, _release.PublishDate, PendingReleaseReason.Fallback);
|
||||||
|
|
||||||
|
Subject.Add(_temporarilyRejected, PendingReleaseReason.Delay);
|
||||||
|
|
||||||
|
VerifyNoInsert();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_remove_duplicate_if_it_is_the_same_release_from_the_same_indexer_twice()
|
||||||
|
{
|
||||||
|
GivenHeldRelease(_release.Title, _release.Indexer, _release.PublishDate, PendingReleaseReason.DownloadClientUnavailable);
|
||||||
|
GivenHeldRelease(_release.Title, _release.Indexer, _release.PublishDate, PendingReleaseReason.Fallback);
|
||||||
|
|
||||||
|
Subject.Add(_temporarilyRejected, PendingReleaseReason.Fallback);
|
||||||
|
|
||||||
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
|
.Verify(v => v.Delete(It.IsAny<int>()), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_add_if_title_is_different()
|
public void should_add_if_title_is_different()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Moq;
|
using Moq;
|
||||||
@@ -26,6 +27,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
private ReleaseInfo _release;
|
private ReleaseInfo _release;
|
||||||
private ParsedEpisodeInfo _parsedEpisodeInfo;
|
private ParsedEpisodeInfo _parsedEpisodeInfo;
|
||||||
private RemoteEpisode _remoteEpisode;
|
private RemoteEpisode _remoteEpisode;
|
||||||
|
private List<PendingRelease> _heldReleases;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@@ -60,17 +62,27 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
_remoteEpisode.Series = _series;
|
_remoteEpisode.Series = _series;
|
||||||
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo;
|
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo;
|
||||||
_remoteEpisode.Release = _release;
|
_remoteEpisode.Release = _release;
|
||||||
|
|
||||||
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary));
|
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary));
|
||||||
|
|
||||||
|
_heldReleases = new List<PendingRelease>();
|
||||||
|
|
||||||
Mocker.GetMock<IPendingReleaseRepository>()
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
.Setup(s => s.All())
|
.Setup(s => s.All())
|
||||||
.Returns(new List<PendingRelease>());
|
.Returns(_heldReleases);
|
||||||
|
|
||||||
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
|
.Setup(s => s.AllBySeriesId(It.IsAny<int>()))
|
||||||
|
.Returns<int>(i => _heldReleases.Where(v => v.SeriesId == i).ToList());
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
||||||
.Returns(_series);
|
.Returns(_series);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Setup(s => s.GetSeries(It.IsAny<IEnumerable<int>>()))
|
||||||
|
.Returns(new List<Series> { _series });
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null))
|
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null))
|
||||||
.Returns(new List<Episode> {_episode});
|
.Returns(new List<Episode> {_episode});
|
||||||
@@ -92,9 +104,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.With(h => h.ParsedEpisodeInfo = parsedEpisodeInfo)
|
.With(h => h.ParsedEpisodeInfo = parsedEpisodeInfo)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IPendingReleaseRepository>()
|
_heldReleases.AddRange(heldReleases);
|
||||||
.Setup(s => s.All())
|
|
||||||
.Returns(heldReleases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
||||||
.Returns(new Series());
|
.Returns(new Series());
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Setup(s => s.GetSeries(It.IsAny<IEnumerable<int>>()))
|
||||||
|
.Returns(new List<Series> { new Series() });
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Series>(), It.IsAny<bool>(), null))
|
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Series>(), It.IsAny<bool>(), null))
|
||||||
.Returns(new List<Episode>{ _episode });
|
.Returns(new List<Episode>{ _episode });
|
||||||
@@ -63,7 +67,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
|
|
||||||
AssertRemoved(1);
|
AssertRemoved(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_remove_multiple_releases_release()
|
public void should_remove_multiple_releases_release()
|
||||||
{
|
{
|
||||||
@@ -134,7 +138,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
|
|
||||||
AssertRemoved(2);
|
AssertRemoved(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertRemoved(params int[] ids)
|
private void AssertRemoved(params int[] ids)
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IPendingReleaseRepository>().Verify(c => c.DeleteMany(It.Is<IEnumerable<int>>(s => s.SequenceEqual(ids))));
|
Mocker.GetMock<IPendingReleaseRepository>().Verify(c => c.DeleteMany(It.Is<IEnumerable<int>>(s => s.SequenceEqual(ids))));
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
_remoteEpisode.Series = _series;
|
_remoteEpisode.Series = _series;
|
||||||
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo;
|
_remoteEpisode.ParsedEpisodeInfo = _parsedEpisodeInfo;
|
||||||
_remoteEpisode.Release = _release;
|
_remoteEpisode.Release = _release;
|
||||||
|
|
||||||
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary));
|
_temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary));
|
||||||
|
|
||||||
Mocker.GetMock<IPendingReleaseRepository>()
|
Mocker.GetMock<IPendingReleaseRepository>()
|
||||||
@@ -73,6 +73,10 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||||||
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
.Setup(s => s.GetSeries(It.IsAny<int>()))
|
||||||
.Returns(_series);
|
.Returns(_series);
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesService>()
|
||||||
|
.Setup(s => s.GetSeries(It.IsAny<IEnumerable<int>>()))
|
||||||
|
.Returns(new List<Series> { _series });
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null))
|
.Setup(s => s.GetEpisodes(It.IsAny<ParsedEpisodeInfo>(), _series, true, null))
|
||||||
.Returns(new List<Episode> {_episode});
|
.Returns(new List<Episode> {_episode});
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||||
|
<channel>
|
||||||
|
<title>Evolution World</title>
|
||||||
|
<description>Advanced RSS Feed for xbtitFM by Petr1fied</description>
|
||||||
|
<link>http://ew.pw</link>
|
||||||
|
<lastBuildDate>Tue, 15 Aug 2017 00:00:00 +0000</lastBuildDate>
|
||||||
|
<copyright>(c) 2017 Evolution World</copyright>
|
||||||
|
<atom:link href="http://ew.pw/advanced_rss.php?cats=34%3B35%3B36%3B37%3B38%3B39%3B41%3B48%3B49%3B50%3B51%3B79%3B80%3B81&tpc=100&auth=secret" rel="self" type="application/rss+xml" />
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<title><![CDATA[[TVShow --> TVShow Bluray 720p] Fargo S01 Complete Season 1 720p BRRip DD5.1 x264-PSYPHER [SEEDERS (3)/LEECHERS (0)]]]></title>
|
||||||
|
<description><![CDATA[<br />Fargo S01 Complete Season 1 720p BRRip DD5.1 x264-PSYPHER<br /><br /><br /><br />Plot:<br /><br />Various chronicles of deception, intrigue and murder in and around frozen Minnesota.<br /><br />Note::-<br />Encode is tested and its perfect, no sync issue there in any episode.<br />All episodes comes with AC3 Audio for better audio and video plaback and English Subs are muxed in video .<br /><br />TECHNiCAL Information:<br /><br /><br />RUNTIME..................: 1 hr x 10<br />Total SIZE...............: 9.75 GiB<br />Total Episodes...........: 10<br />VIDEO CODEC..............: x264 2nd Pass (High,L4.1)<br />RESOLUTION...............: 1280x720<br />BITRATE (Video)..........: 2100 Kbps - 2400 kbps<br />Aspect Ratio.............: 16:9<br />Video Container..........: MKV<br />FRAMERATE................: 23.967 fps<br />AUDIO....................: English AC3 6 Channel 384 kbps<br />SUBTITLES................: English, English (SDH)<br />CHAPTERS.................: Yes<br />SOURCE...................: DON (Thanks !)<br /><br /><br />GENRE...................: Crime | Drama | Thriller<br />RATING..................: 9.1/10 from 140,765 users<br />IMDB link...............: <a href="http://www.imdb.com/title/tt2802850/" target="_blank">http://www.imdb.com/title/tt2802850/</a>]]></description>
|
||||||
|
<link>http://ew.pw/index.php?page=torrent-details&id=dea071a7a62a0d662538d46402fb112f30b8c9fa</link>
|
||||||
|
<guid>http://ew.pw/index.php?page=torrent-details&id=dea071a7a62a0d662538d46402fb112f30b8c9fa</guid>
|
||||||
|
<enclosure url="http://ew.pw/download.php?id=dea071a7a62a0d662538d46402fb112f30b8c9fa&f=Fargo%20S01%20Complete%20Season%201%20720p%20BRRip%20DD5.1%20x264-PSYPHER.torrent&auth=secret" length="13625" type="application/x-bittorrent" />
|
||||||
|
<pubDate>Sun, 13 Aug 2017 22:21:43 +0000</pubDate>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<title><![CDATA[[TVShow --> TVShow Bluray 720p] American Horror Story S04 Complete Season 4 720p BRRip DD5.1 x264 - PSYPHER [SEEDERS (2)/LEECHERS (0)]]]></title>
|
||||||
|
<description><![CDATA[]]></description>
|
||||||
|
<link>http://ew.pw/index.php?page=torrent-details&id=2725fe19ea2addf5aafbd523d134191b8abbb2ee</link>
|
||||||
|
<guid>http://ew.pw/index.php?page=torrent-details&id=2725fe19ea2addf5aafbd523d134191b8abbb2ee</guid>
|
||||||
|
<enclosure url="http://ew.pw/download.php?id=2725fe19ea2addf5aafbd523d134191b8abbb2ee&f=American%20Horror%20Story%20S04%20Complete%20Season%204%20720p%20BRRip%20DD5.1%20x264%20-%20PSYPHER.torrent&auth=secret" length="16583" type="application/x-bittorrent" />
|
||||||
|
<pubDate>Fri, 28 Jul 2017 16:29:51 +0000</pubDate>
|
||||||
|
</item>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Housekeeping.Housekeepers;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider.Status;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class FixFutureDownloadClientStatusTimesFixture : CoreTest<FixFutureDownloadClientStatusTimes>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_set_disabled_till_when_its_too_far_in_the_future()
|
||||||
|
{
|
||||||
|
var disabledTillTime = EscalationBackOff.Periods[1];
|
||||||
|
var downloadClientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.EscalationLevel = 1)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(downloadClientStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<DownloadClientStatus>>(i => i.All(
|
||||||
|
s => s.DisabledTill.Value < DateTime.UtcNow.AddMinutes(disabledTillTime)))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_set_initial_failure_when_its_in_the_future()
|
||||||
|
{
|
||||||
|
var downloadClientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.EscalationLevel = 1)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(downloadClientStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<DownloadClientStatus>>(i => i.All(
|
||||||
|
s => s.InitialFailure.Value <= DateTime.UtcNow))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_set_most_recent_failure_when_its_in_the_future()
|
||||||
|
{
|
||||||
|
var downloadClientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(5))
|
||||||
|
.With(t => t.EscalationLevel = 1)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(downloadClientStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<DownloadClientStatus>>(i => i.All(
|
||||||
|
s => s.MostRecentFailure.Value <= DateTime.UtcNow))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_change_statuses_when_times_are_in_the_past()
|
||||||
|
{
|
||||||
|
var downloadClientStatuses = Builder<DownloadClientStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.EscalationLevel = 0)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(downloadClientStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDownloadClientStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<DownloadClientStatus>>(i => i.Count == 0)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Housekeeping.Housekeepers;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.ThingiProvider.Status;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class FixFutureIndexerStatusTimesFixture : CoreTest<FixFutureIndexerStatusTimes>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_set_disabled_till_when_its_too_far_in_the_future()
|
||||||
|
{
|
||||||
|
var disabledTillTime = EscalationBackOff.Periods[1];
|
||||||
|
var indexerStatuses = Builder<IndexerStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.EscalationLevel = 1)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(indexerStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<IndexerStatus>>(i => i.All(
|
||||||
|
s => s.DisabledTill.Value < DateTime.UtcNow.AddMinutes(disabledTillTime)))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_set_initial_failure_when_its_in_the_future()
|
||||||
|
{
|
||||||
|
var indexerStatuses = Builder<IndexerStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.EscalationLevel = 1)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(indexerStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<IndexerStatus>>(i => i.All(
|
||||||
|
s => s.InitialFailure.Value <= DateTime.UtcNow))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_set_most_recent_failure_when_its_in_the_future()
|
||||||
|
{
|
||||||
|
var indexerStatuses = Builder<IndexerStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(5))
|
||||||
|
.With(t => t.EscalationLevel = 1)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(indexerStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<IndexerStatus>>(i => i.All(
|
||||||
|
s => s.MostRecentFailure.Value <= DateTime.UtcNow))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_change_statuses_when_times_are_in_the_past()
|
||||||
|
{
|
||||||
|
var indexerStatuses = Builder<IndexerStatus>.CreateListOfSize(5)
|
||||||
|
.All()
|
||||||
|
.With(t => t.DisabledTill = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.InitialFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.MostRecentFailure = DateTime.UtcNow.AddDays(-5))
|
||||||
|
.With(t => t.EscalationLevel = 0)
|
||||||
|
.BuildListOfNew();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(indexerStatuses);
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<IIndexerStatusRepository>()
|
||||||
|
.Verify(v => v.UpdateMany(
|
||||||
|
It.Is<List<IndexerStatus>>(i => i.Count == 0)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using System;
|
|
||||||
using FizzWare.NBuilder;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Microsoft.Practices.ObjectBuilder2;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Core.Housekeeping.Housekeepers;
|
|
||||||
using NzbDrone.Core.Jobs;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class FixFutureRunScheduledTasksFixture : DbTest<FixFutureRunScheduledTasks, ScheduledTask>
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void should_set_last_execution_time_to_now_when_its_in_the_future()
|
|
||||||
{
|
|
||||||
var tasks = Builder<ScheduledTask>.CreateListOfSize(5)
|
|
||||||
.All()
|
|
||||||
.With(t => t.LastExecution = DateTime.UtcNow.AddDays(5))
|
|
||||||
.BuildListOfNew();
|
|
||||||
|
|
||||||
Db.InsertMany(tasks);
|
|
||||||
|
|
||||||
Subject.Clean();
|
|
||||||
|
|
||||||
AllStoredModels.ForEach(t => t.LastExecution.Should().BeBefore(DateTime.UtcNow));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_not_change_last_execution_time_when_its_in_the_past()
|
|
||||||
{
|
|
||||||
var expectedTime = DateTime.UtcNow.AddHours(-1);
|
|
||||||
|
|
||||||
var tasks = Builder<ScheduledTask>.CreateListOfSize(5)
|
|
||||||
.All()
|
|
||||||
.With(t => t.LastExecution = expectedTime)
|
|
||||||
.BuildListOfNew();
|
|
||||||
|
|
||||||
Db.InsertMany(tasks);
|
|
||||||
|
|
||||||
Subject.Clean();
|
|
||||||
|
|
||||||
AllStoredModels.ForEach(t => t.LastExecution.Should().Be(expectedTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,6 +30,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||||||
[TestCase("100 Kb/s")]
|
[TestCase("100 Kb/s")]
|
||||||
[TestCase(" 12341234")]
|
[TestCase(" 12341234")]
|
||||||
[TestCase("12341234 other")]
|
[TestCase("12341234 other")]
|
||||||
|
[TestCase("")]
|
||||||
public void should_not_parse_size(string sizeString)
|
public void should_not_parse_size(string sizeString)
|
||||||
{
|
{
|
||||||
var result = RssParser.ParseSize(sizeString, true);
|
var result = RssParser.ParseSize(sizeString, true);
|
||||||
|
|||||||
@@ -261,6 +261,33 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
|
|||||||
torrentInfo.DownloadUrl.Should().Be("https://alpharatio.cc/torrents.php?action=download&authkey=private_auth_key&torrent_pass=private_torrent_pass&id=465831");
|
torrentInfo.DownloadUrl.Should().Be("https://alpharatio.cc/torrents.php?action=download&authkey=private_auth_key&torrent_pass=private_torrent_pass&id=465831");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_parse_recent_feed_from_EveolutionWorld_without_size()
|
||||||
|
{
|
||||||
|
Subject.Definition.Settings.As<TorrentRssIndexerSettings>().AllowZeroSize = true;
|
||||||
|
GivenRecentFeedResponse("TorrentRss/EvolutionWorld.xml");
|
||||||
|
|
||||||
|
var releases = Subject.FetchRecent();
|
||||||
|
|
||||||
|
releases.Should().HaveCount(2);
|
||||||
|
releases.First().Should().BeOfType<TorrentInfo>();
|
||||||
|
|
||||||
|
var torrentInfo = releases.First() as TorrentInfo;
|
||||||
|
|
||||||
|
torrentInfo.Title.Should().Be("[TVShow --> TVShow Bluray 720p] Fargo S01 Complete Season 1 720p BRRip DD5.1 x264-PSYPHER [SEEDERS (3)/LEECHERS (0)]");
|
||||||
|
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
|
||||||
|
torrentInfo.DownloadUrl.Should().Be("http://ew.pw/download.php?id=dea071a7a62a0d662538d46402fb112f30b8c9fa&f=Fargo%20S01%20Complete%20Season%201%20720p%20BRRip%20DD5.1%20x264-PSYPHER.torrent&auth=secret");
|
||||||
|
torrentInfo.InfoUrl.Should().BeNullOrEmpty();
|
||||||
|
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
|
||||||
|
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
|
||||||
|
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2017-08-13T22:21:43Z").ToUniversalTime());
|
||||||
|
torrentInfo.Size.Should().Be(0);
|
||||||
|
torrentInfo.InfoHash.Should().BeNull();
|
||||||
|
torrentInfo.MagnetUrl.Should().BeNull();
|
||||||
|
torrentInfo.Peers.Should().NotHaveValue();
|
||||||
|
torrentInfo.Seeders.Should().NotHaveValue();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_record_indexer_failure_if_unsupported_feed()
|
public void should_record_indexer_failure_if_unsupported_feed()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
@@ -269,6 +269,22 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_scan_files_that_start_with_period()
|
||||||
|
{
|
||||||
|
GivenSeriesFolder();
|
||||||
|
|
||||||
|
GivenFiles(new List<string>
|
||||||
|
{
|
||||||
|
Path.Combine(_series.Path, "Season 1", ".s01e01.mkv").AsOsAgnostic()
|
||||||
|
});
|
||||||
|
|
||||||
|
Subject.Scan(_series);
|
||||||
|
|
||||||
|
Mocker.GetMock<IMakeImportDecision>()
|
||||||
|
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_not_scan_subfolder_of_season_folder_that_starts_with_a_period()
|
public void should_not_scan_subfolder_of_season_folder_that_starts_with_a_period()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
_quality = new QualityModel(Quality.DVD);
|
_quality = new QualityModel(Quality.DVD);
|
||||||
|
|
||||||
_localEpisode = new LocalEpisode
|
_localEpisode = new LocalEpisode
|
||||||
{
|
{
|
||||||
Series = _series,
|
Series = _series,
|
||||||
Quality = _quality,
|
Quality = _quality,
|
||||||
Episodes = new List<Episode> { new Episode() },
|
Episodes = new List<Episode> { new Episode() },
|
||||||
@@ -231,7 +231,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Setup(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()))
|
.Setup(c => c.GetLocalEpisode(It.IsAny<string>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()))
|
||||||
.Returns(new LocalEpisode() { Path = "test" });
|
.Returns(new LocalEpisode() { Path = "test", ParsedEpisodeInfo = new ParsedEpisodeInfo { } });
|
||||||
|
|
||||||
_videoFiles = new List<string>
|
_videoFiles = new List<string>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
@@ -104,6 +104,20 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
|
|||||||
MediaInfoFormatter.FormatAudioChannels(mediaInfoModel).Should().Be(7.1m);
|
MediaInfoFormatter.FormatAudioChannels(mediaInfoModel).Should().Be(7.1m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_skip_empty_groups_in_AudioChannelPositions()
|
||||||
|
{
|
||||||
|
var mediaInfoModel = new MediaInfoModel
|
||||||
|
{
|
||||||
|
AudioChannels = 2,
|
||||||
|
AudioChannelPositions = " / 2/0/0.0",
|
||||||
|
AudioChannelPositionsText = null,
|
||||||
|
SchemaRevision = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaInfoFormatter.FormatAudioChannels(mediaInfoModel).Should().Be(2);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_sum_first_series_of_numbers_from_AudioChannelPositions()
|
public void should_sum_first_series_of_numbers_from_AudioChannelPositions()
|
||||||
{
|
{
|
||||||
@@ -117,5 +131,19 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
|
|||||||
|
|
||||||
MediaInfoFormatter.FormatAudioChannels(mediaInfoModel).Should().Be(7.1m);
|
MediaInfoFormatter.FormatAudioChannels(mediaInfoModel).Should().Be(7.1m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_sum_dual_mono_representation_AudioChannelPositions()
|
||||||
|
{
|
||||||
|
var mediaInfoModel = new MediaInfoModel
|
||||||
|
{
|
||||||
|
AudioChannels = 2,
|
||||||
|
AudioChannelPositions = "1+1",
|
||||||
|
AudioChannelPositionsText = null,
|
||||||
|
SchemaRevision = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaInfoFormatter.FormatAudioChannels(mediaInfoModel).Should().Be(2.0m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||||||
.All()
|
.All()
|
||||||
.With(v => v.RelativePath = "media.mkv")
|
.With(v => v.RelativePath = "media.mkv")
|
||||||
.TheFirst(1)
|
.TheFirst(1)
|
||||||
.With(v => v.MediaInfo = new MediaInfoModel { SchemaRevision = UpdateMediaInfoService.CURRENT_MEDIA_INFO_SCHEMA_REVISION })
|
.With(v => v.MediaInfo = new MediaInfoModel { SchemaRevision = VideoFileInfoReader.CURRENT_MEDIA_INFO_SCHEMA_REVISION })
|
||||||
.BuildList();
|
.BuildList();
|
||||||
|
|
||||||
Mocker.GetMock<IMediaFileService>()
|
Mocker.GetMock<IMediaFileService>()
|
||||||
@@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||||||
.All()
|
.All()
|
||||||
.With(v => v.RelativePath = "media.mkv")
|
.With(v => v.RelativePath = "media.mkv")
|
||||||
.TheFirst(1)
|
.TheFirst(1)
|
||||||
.With(v => v.MediaInfo = new MediaInfoModel { SchemaRevision = UpdateMediaInfoService.MINIMUM_MEDIA_INFO_SCHEMA_REVISION })
|
.With(v => v.MediaInfo = new MediaInfoModel { SchemaRevision = VideoFileInfoReader.MINIMUM_MEDIA_INFO_SCHEMA_REVISION })
|
||||||
.BuildList();
|
.BuildList();
|
||||||
|
|
||||||
Mocker.GetMock<IMediaFileService>()
|
Mocker.GetMock<IMediaFileService>()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
@@ -7,6 +7,7 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
@@ -33,12 +34,16 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Setup(c => c.FileExists(It.IsAny<string>()))
|
.Setup(c => c.FolderExists(Directory.GetParent(_localEpisode.Series.Path).FullName))
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Setup(c => c.GetParentFolder(It.IsAny<string>()))
|
.Setup(c => c.FileExists(It.IsAny<string>()))
|
||||||
.Returns<string>(c => Path.GetDirectoryName(c));
|
.Returns(true);
|
||||||
|
|
||||||
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
.Setup(c => c.GetParentFolder(It.IsAny<string>()))
|
||||||
|
.Returns<string>(c => Path.GetDirectoryName(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenSingleEpisodeWithSingleEpisodeFile()
|
private void GivenSingleEpisodeWithSingleEpisodeFile()
|
||||||
@@ -175,5 +180,19 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
|
|
||||||
Subject.UpgradeEpisodeFile(_episodeFile, _localEpisode).OldFiles.Count.Should().Be(2);
|
Subject.UpgradeEpisodeFile(_episodeFile, _localEpisode).OldFiles.Count.Should().Be(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_throw_if_there_are_existing_episode_files_and_the_root_folder_is_missing()
|
||||||
|
{
|
||||||
|
GivenSingleEpisodeWithSingleEpisodeFile();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
.Setup(c => c.FolderExists(Directory.GetParent(_localEpisode.Series.Path).FullName))
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
|
Assert.Throws<RootFolderNotFoundException>(() => Subject.UpgradeEpisodeFile(_episodeFile, _localEpisode));
|
||||||
|
|
||||||
|
Mocker.GetMock<IMediaFileService>().Verify(v => v.Delete(_localEpisode.Episodes.Single().EpisodeFile.Value, DeleteMediaFileReason.Upgrade), Times.Never());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,15 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
.Returns(_executorB.Object);
|
.Returns(_executorB.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
Subject.Handle(new ApplicationShutdownRequested());
|
||||||
|
|
||||||
|
// Give the threads a bit of time to shut down.
|
||||||
|
Thread.Sleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
private void GivenCommandQueue()
|
private void GivenCommandQueue()
|
||||||
{
|
{
|
||||||
_commandQueue = new BlockingCollection<CommandModel>(new CommandQueue());
|
_commandQueue = new BlockingCollection<CommandModel>(new CommandQueue());
|
||||||
@@ -44,8 +53,10 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
.Returns(_commandQueue.GetConsumingEnumerable);
|
.Returns(_commandQueue.GetConsumingEnumerable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WaitForExecution(CommandModel commandModel)
|
private void QueueAndWaitForExecution(CommandModel commandModel)
|
||||||
{
|
{
|
||||||
|
Thread.Sleep(10);
|
||||||
|
|
||||||
Mocker.GetMock<IManageCommandQueue>()
|
Mocker.GetMock<IManageCommandQueue>()
|
||||||
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), It.IsAny<string>()))
|
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), It.IsAny<string>()))
|
||||||
.Callback(() => _commandExecuted = true);
|
.Callback(() => _commandExecuted = true);
|
||||||
@@ -54,12 +65,14 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
.Setup(s => s.Fail(It.Is<CommandModel>(c => c == commandModel), It.IsAny<string>(), It.IsAny<Exception>()))
|
.Setup(s => s.Fail(It.Is<CommandModel>(c => c == commandModel), It.IsAny<string>(), It.IsAny<Exception>()))
|
||||||
.Callback(() => _commandExecuted = true);
|
.Callback(() => _commandExecuted = true);
|
||||||
|
|
||||||
|
_commandQueue.Add(commandModel);
|
||||||
|
|
||||||
while (!_commandExecuted)
|
while (!_commandExecuted)
|
||||||
{
|
{
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
var t1 = 1;
|
Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -82,9 +95,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
};
|
};
|
||||||
|
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
_commandQueue.Add(commandModel);
|
|
||||||
|
|
||||||
WaitForExecution(commandModel);
|
QueueAndWaitForExecution(commandModel);
|
||||||
|
|
||||||
_executorA.Verify(c => c.Execute(commandA), Times.Once());
|
_executorA.Verify(c => c.Execute(commandA), Times.Once());
|
||||||
}
|
}
|
||||||
@@ -100,9 +112,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
};
|
};
|
||||||
|
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
_commandQueue.Add(commandModel);
|
|
||||||
|
|
||||||
WaitForExecution(commandModel);
|
QueueAndWaitForExecution(commandModel);
|
||||||
|
|
||||||
_executorA.Verify(c => c.Execute(commandA), Times.Once());
|
_executorA.Verify(c => c.Execute(commandA), Times.Once());
|
||||||
_executorB.Verify(c => c.Execute(It.IsAny<CommandB>()), Times.Never());
|
_executorB.Verify(c => c.Execute(It.IsAny<CommandB>()), Times.Never());
|
||||||
@@ -122,9 +133,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
.Throws(new NotImplementedException());
|
.Throws(new NotImplementedException());
|
||||||
|
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
_commandQueue.Add(commandModel);
|
|
||||||
|
|
||||||
WaitForExecution(commandModel);
|
QueueAndWaitForExecution(commandModel);
|
||||||
|
|
||||||
VerifyEventPublished<CommandExecutedEvent>();
|
VerifyEventPublished<CommandExecutedEvent>();
|
||||||
ExceptionVerification.ExpectedErrors(1);
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
@@ -141,9 +151,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
};
|
};
|
||||||
|
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
_commandQueue.Add(commandModel);
|
|
||||||
|
|
||||||
WaitForExecution(commandModel);
|
QueueAndWaitForExecution(commandModel);
|
||||||
|
|
||||||
VerifyEventPublished<CommandExecutedEvent>();
|
VerifyEventPublished<CommandExecutedEvent>();
|
||||||
}
|
}
|
||||||
@@ -159,9 +168,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
};
|
};
|
||||||
|
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
_commandQueue.Add(commandModel);
|
|
||||||
|
|
||||||
WaitForExecution(commandModel);
|
QueueAndWaitForExecution(commandModel);
|
||||||
|
|
||||||
Mocker.GetMock<IManageCommandQueue>()
|
Mocker.GetMock<IManageCommandQueue>()
|
||||||
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandA.CompletionMessage))
|
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandA.CompletionMessage))
|
||||||
@@ -180,9 +188,8 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
};
|
};
|
||||||
|
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
_commandQueue.Add(commandModel);
|
|
||||||
|
|
||||||
WaitForExecution(commandModel);
|
QueueAndWaitForExecution(commandModel);
|
||||||
|
|
||||||
Mocker.GetMock<IManageCommandQueue>()
|
Mocker.GetMock<IManageCommandQueue>()
|
||||||
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandModel.Message))
|
.Setup(s => s.Complete(It.Is<CommandModel>(c => c == commandModel), commandModel.Message))
|
||||||
@@ -202,10 +209,10 @@ namespace NzbDrone.Core.Test.Messaging.Commands
|
|||||||
|
|
||||||
public CommandB()
|
public CommandB()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string CompletionMessage => null;
|
public override string CompletionMessage => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,10 @@
|
|||||||
<HintPath>..\packages\Unity.2.1.505.2\lib\NET35\Microsoft.Practices.Unity.Configuration.dll</HintPath>
|
<HintPath>..\packages\Unity.2.1.505.2\lib\NET35\Microsoft.Practices.Unity.Configuration.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="NCrunch.Framework, Version=3.2.0.3, Culture=neutral, PublicKeyToken=01d101bf6f3e0aea, processorArchitecture=MSIL">
|
<Reference Include="NCrunch.Framework, Version=3.2.0.3, Culture=neutral, PublicKeyToken=01d101bf6f3e0aea, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NCrunch.Framework.3.2.0.3\lib\NCrunch.Framework.dll</HintPath>
|
<HintPath>..\packages\NCrunch.Framework.3.2.0.3\lib\NCrunch.Framework.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
@@ -86,7 +90,7 @@
|
|||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
|
||||||
@@ -97,9 +101,6 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920">
|
|
||||||
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Prowlin">
|
<Reference Include="Prowlin">
|
||||||
<HintPath>..\packages\Prowlin.0.9.4456.26422\lib\net40\Prowlin.dll</HintPath>
|
<HintPath>..\packages\Prowlin.0.9.4456.26422\lib\net40\Prowlin.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -241,7 +242,8 @@
|
|||||||
<Compile Include="Housekeeping\Housekeepers\CleanupDownloadClientUnavailablePendingReleasesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupDownloadClientUnavailablePendingReleasesFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupUnusedTagsFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupUnusedTagsFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedPendingReleasesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedPendingReleasesFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\FixFutureRunScheduledTasksFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\FixFutureDownloadClientStatusTimesFixture.cs" />
|
||||||
|
<Compile Include="Housekeeping\Housekeepers\FixFutureIndexerStatusTimesFixture.cs" />
|
||||||
<Compile Include="Http\HttpProxySettingsProviderFixture.cs" />
|
<Compile Include="Http\HttpProxySettingsProviderFixture.cs" />
|
||||||
<Compile Include="Http\TorCacheHttpRequestInterceptorFixture.cs" />
|
<Compile Include="Http\TorCacheHttpRequestInterceptorFixture.cs" />
|
||||||
<Compile Include="IndexerSearchTests\SeriesSearchServiceFixture.cs" />
|
<Compile Include="IndexerSearchTests\SeriesSearchServiceFixture.cs" />
|
||||||
@@ -432,6 +434,10 @@
|
|||||||
<Link>sqlite3.dll</Link>
|
<Link>sqlite3.dll</Link>
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="Files\Indexers\TorrentRss\EvolutionWorld.xml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Files\Indexers\TorrentRss\AlphaRatio.xml">
|
<Content Include="Files\Indexers\TorrentRss\AlphaRatio.xml">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
@@ -46,6 +46,9 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUNDUB-LOL", Language.Hungarian)]
|
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUNDUB-LOL", Language.Hungarian)]
|
||||||
[TestCase("Castle.2009.S01E14.HDTV.XviD.ENG.HUN-LOL", Language.Hungarian)]
|
[TestCase("Castle.2009.S01E14.HDTV.XviD.ENG.HUN-LOL", Language.Hungarian)]
|
||||||
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUN-LOL", Language.Hungarian)]
|
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUN-LOL", Language.Hungarian)]
|
||||||
|
[TestCase("Avatar.The.Last.Airbender.S01-03.DVDRip.HebDub",Language.Hebrew)]
|
||||||
|
[TestCase("Prison.Break.S05E01.WEBRip.x264.AC3.LT.EN-CNN", Language.Lithuanian)]
|
||||||
|
[TestCase("The.Walking.Dead.S07E11.WEB Rip.XviD.Louige-CZ.EN.5.1", Language.Czech)]
|
||||||
public void should_parse_language(string postTitle, Language language)
|
public void should_parse_language(string postTitle, Language language)
|
||||||
{
|
{
|
||||||
var result = LanguageParser.ParseLanguage(postTitle);
|
var result = LanguageParser.ParseLanguage(postTitle);
|
||||||
|
|||||||
@@ -72,5 +72,13 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
Parser.Parser.ParseTitle(title).Quality.Quality.Should().NotBe(Quality.Unknown);
|
Parser.Parser.ParseTitle(title).Quality.Quality.Should().NotBe(Quality.Unknown);
|
||||||
Parser.Parser.ParseTitle(title).Quality.QualitySource.Should().Be(QualitySource.Extension);
|
Parser.Parser.ParseTitle(title).Quality.QualitySource.Should().Be(QualitySource.Extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestCase("Revolution.S01E02.Chained.Heat.mkv", "Revolution.S01E02.Chained.Heat")]
|
||||||
|
public void should_parse_releasetitle(string path, string releaseTitle)
|
||||||
|
{
|
||||||
|
var result = Parser.Parser.ParseTitle(path);
|
||||||
|
result.ReleaseTitle.Should().Be(releaseTitle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Glee.S04E10.Glee.Actually.480p.WEB-DL.x264-mSD", false)]
|
[TestCase("Glee.S04E10.Glee.Actually.480p.WEB-DL.x264-mSD", false)]
|
||||||
[TestCase("The.Big.Bang.Theory.S06E11.The.Santa.Simulation.480p.WEB-DL.x264-mSD", false)]
|
[TestCase("The.Big.Bang.Theory.S06E11.The.Santa.Simulation.480p.WEB-DL.x264-mSD", false)]
|
||||||
[TestCase("Da.Vincis.Demons.S02E04.480p.WEB.DL.nSD.x264-NhaNc3", false)]
|
[TestCase("Da.Vincis.Demons.S02E04.480p.WEB.DL.nSD.x264-NhaNc3", false)]
|
||||||
|
[TestCase("Incorporated.S01E08.Das.geloeschte.Ich.German.Dubbed.DL.AmazonHD.x264-TVS", false)]
|
||||||
|
[TestCase("Haters.Back.Off.S01E04.Rod.Trip.mit.meinem.Onkel.German.DL.NetflixUHD.x264", false)]
|
||||||
public void should_parse_webdl480p_quality(string title, bool proper)
|
public void should_parse_webdl480p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.WEBDL480p, proper);
|
ParseAndVerifyQuality(title, Quality.WEBDL480p, proper);
|
||||||
@@ -145,6 +147,9 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Castle.S06E23.720p.WebHD.h264-euHD", false)]
|
[TestCase("Castle.S06E23.720p.WebHD.h264-euHD", false)]
|
||||||
[TestCase("The.Nightly.Show.2016.03.14.720p.WEB.x264-spamTV", false)]
|
[TestCase("The.Nightly.Show.2016.03.14.720p.WEB.x264-spamTV", false)]
|
||||||
[TestCase("The.Nightly.Show.2016.03.14.720p.WEB.h264-spamTV", false)]
|
[TestCase("The.Nightly.Show.2016.03.14.720p.WEB.h264-spamTV", false)]
|
||||||
|
[TestCase("Incorporated.S01E08.Das.geloeschte.Ich.German.DD51.Dubbed.DL.720p.AmazonHD.x264-TVS", false)]
|
||||||
|
[TestCase("Marco.Polo.S01E11.One.Hundred.Eyes.2015.German.DD51.DL.720p.NetflixUHD.x264.NewUp.by.Wunschtante", false)]
|
||||||
|
[TestCase("Hush 2016 German DD51 DL 720p NetflixHD x264-TVS", false)]
|
||||||
public void should_parse_webdl720p_quality(string title, bool proper)
|
public void should_parse_webdl720p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.WEBDL720p, proper);
|
ParseAndVerifyQuality(title, Quality.WEBDL720p, proper);
|
||||||
@@ -166,6 +171,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Series Title S06E08 No One PROPER 1080p WEB DD5 1 H 264-EXCLUSIVE", true)]
|
[TestCase("Series Title S06E08 No One PROPER 1080p WEB DD5 1 H 264-EXCLUSIVE", true)]
|
||||||
[TestCase("Series Title S06E08 No One PROPER 1080p WEB H 264-EXCLUSIVE", true)]
|
[TestCase("Series Title S06E08 No One PROPER 1080p WEB H 264-EXCLUSIVE", true)]
|
||||||
[TestCase("The.Simpsons.S25E21.Pay.Pal.1080p.WEB-DL.DD5.1.H.264-NTb", false)]
|
[TestCase("The.Simpsons.S25E21.Pay.Pal.1080p.WEB-DL.DD5.1.H.264-NTb", false)]
|
||||||
|
[TestCase("Incorporated.S01E08.Das.geloeschte.Ich.German.DD51.Dubbed.DL.1080p.AmazonHD.x264-TVS", false)]
|
||||||
|
[TestCase("Death.Note.2017.German.DD51.DL.1080p.NetflixHD.x264-TVS", false)]
|
||||||
public void should_parse_webdl1080p_quality(string title, bool proper)
|
public void should_parse_webdl1080p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.WEBDL1080p, proper);
|
ParseAndVerifyQuality(title, Quality.WEBDL1080p, proper);
|
||||||
@@ -178,6 +185,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.x264-spamTV", false)]
|
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.x264-spamTV", false)]
|
||||||
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.h264-spamTV", false)]
|
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.h264-spamTV", false)]
|
||||||
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.PROPER.h264-spamTV", true)]
|
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.PROPER.h264-spamTV", true)]
|
||||||
|
[TestCase("House.of.Cards.US.s05e13.4K.UHD.WEB.DL", false)]
|
||||||
|
[TestCase("House.of.Cards.US.s05e13.UHD.4K.WEB.DL", false)]
|
||||||
public void should_parse_webdl2160p_quality(string title, bool proper)
|
public void should_parse_webdl2160p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.WEBDL2160p, proper);
|
ParseAndVerifyQuality(title, Quality.WEBDL2160p, proper);
|
||||||
@@ -215,6 +224,13 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
ParseAndVerifyQuality(title, Quality.Bluray1080p, proper);
|
ParseAndVerifyQuality(title, Quality.Bluray1080p, proper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("House.of.Cards.US.s05e13.4K.UHD.Bluray", false)]
|
||||||
|
[TestCase("House.of.Cards.US.s05e13.UHD.4K.Bluray", false)]
|
||||||
|
public void should_parse_bluray2160p_quality(string title, bool proper)
|
||||||
|
{
|
||||||
|
ParseAndVerifyQuality(title, Quality.Bluray2160p, proper);
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase("POI S02E11 1080i HDTV DD5.1 MPEG2-TrollHD", false)]
|
[TestCase("POI S02E11 1080i HDTV DD5.1 MPEG2-TrollHD", false)]
|
||||||
[TestCase("How I Met Your Mother S01E18 Nothing Good Happens After 2 A.M. 720p HDTV DD5.1 MPEG2-TrollHD", false)]
|
[TestCase("How I Met Your Mother S01E18 Nothing Good Happens After 2 A.M. 720p HDTV DD5.1 MPEG2-TrollHD", false)]
|
||||||
[TestCase("The Voice S01E11 The Finals 1080i HDTV DD5.1 MPEG2-TrollHD", false)]
|
[TestCase("The Voice S01E11 The Finals 1080i HDTV DD5.1 MPEG2-TrollHD", false)]
|
||||||
|
|||||||
@@ -34,24 +34,47 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
result.FullSeason.Should().BeTrue();
|
result.FullSeason.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER")]
|
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER", "Acropolis Now", 5)]
|
||||||
[TestCase("Punky Brewster S01 EXTRAS DVDRip XviD RUNNER")]
|
[TestCase("Punky Brewster S01 EXTRAS DVDRip XviD RUNNER", "Punky Brewster", 1)]
|
||||||
[TestCase("Instant Star S03 EXTRAS DVDRip XviD OSiTV")]
|
[TestCase("Instant Star S03 EXTRAS DVDRip XviD OSiTV", "Instant Star", 3)]
|
||||||
public void should_parse_season_extras(string postTitle)
|
[TestCase("The.Flash.S03.Extras.01.Deleted.Scenes.720p", "The Flash", 3)]
|
||||||
|
[TestCase("The.Flash.S03.Extras.02.720p", "The Flash", 3)]
|
||||||
|
public void should_parse_season_extras(string postTitle, string title, int season)
|
||||||
{
|
{
|
||||||
var result = Parser.Parser.ParseTitle(postTitle);
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
result.SeasonNumber.Should().Be(season);
|
||||||
result.Should().BeNull();
|
result.SeriesTitle.Should().Be(title);
|
||||||
|
result.EpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.FullSeason.Should().BeTrue();
|
||||||
|
result.IsSeasonExtra.Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("Lie.to.Me.S03.SUBPACK.DVDRip.XviD-REWARD")]
|
[TestCase("Lie.to.Me.S03.SUBPACK.DVDRip.XviD-REWARD", "Lie to Me", 3)]
|
||||||
[TestCase("The.Middle.S02.SUBPACK.DVDRip.XviD-REWARD")]
|
[TestCase("The.Middle.S02.SUBPACK.DVDRip.XviD-REWARD", "The Middle", 2)]
|
||||||
[TestCase("CSI.S11.SUBPACK.DVDRip.XviD-REWARD")]
|
[TestCase("CSI.S11.SUBPACK.DVDRip.XviD-REWARD", "CSI", 11)]
|
||||||
public void should_parse_season_subpack(string postTitle)
|
public void should_parse_season_subpack(string postTitle, string title, int season)
|
||||||
{
|
{
|
||||||
var result = Parser.Parser.ParseTitle(postTitle);
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
result.SeasonNumber.Should().Be(season);
|
||||||
|
result.SeriesTitle.Should().Be(title);
|
||||||
|
result.EpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.FullSeason.Should().BeTrue();
|
||||||
|
result.IsSeasonExtra.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
result.Should().BeNull();
|
[TestCase("The.Ranch.2016.S02.Part.1.1080p.NF.WEBRip.DD5.1.x264-NTb", "The Ranch 2016", 2, 1)]
|
||||||
|
public void should_parse_partial_season_release(string postTitle, string title, int season, int seasonPart)
|
||||||
|
{
|
||||||
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
result.SeasonNumber.Should().Be(season);
|
||||||
|
result.SeriesTitle.Should().Be(title);
|
||||||
|
result.EpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.FullSeason.Should().BeFalse();
|
||||||
|
result.IsPartialSeason.Should().BeTrue();
|
||||||
|
result.SeasonPart.Should().Be(seasonPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeMonitoredServiceTests
|
|||||||
Subject.SetEpisodeMonitoredStatus(_series, null);
|
Subject.SetEpisodeMonitoredStatus(_series, null);
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Once());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Once());
|
||||||
|
|
||||||
Mocker.GetMock<IEpisodeService>()
|
Mocker.GetMock<IEpisodeService>()
|
||||||
.Verify(v => v.UpdateEpisodes(It.IsAny<List<Episode>>()), Times.Never());
|
.Verify(v => v.UpdateEpisodes(It.IsAny<List<Episode>>()), Times.Never());
|
||||||
@@ -249,13 +249,13 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeMonitoredServiceTests
|
|||||||
private void VerifySeasonMonitored(Func<Season, bool> predicate)
|
private void VerifySeasonMonitored(Func<Season, bool> predicate)
|
||||||
{
|
{
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Where(predicate).All(n => n.Monitored))));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Where(predicate).All(n => n.Monitored)), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VerifySeasonNotMonitored(Func<Season, bool> predicate)
|
private void VerifySeasonNotMonitored(Func<Season, bool> predicate)
|
||||||
{
|
{
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Where(predicate).All(n => !n.Monitored))));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Where(predicate).All(n => !n.Monitored)), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
ExceptionVerification.ExpectedErrors(1);
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -81,7 +81,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(_command);
|
Subject.Execute(_command);
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Path == expectedPath)), Times.Once());
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Path == expectedPath), It.IsAny<bool>()), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(_command);
|
Subject.Execute(_command);
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Path == _command.DestinationPath)), Times.Once());
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Path == _command.DestinationPath), It.IsAny<bool>()), Times.Once());
|
||||||
|
|
||||||
Mocker.GetMock<IBuildFileNames>()
|
Mocker.GetMock<IBuildFileNames>()
|
||||||
.Verify(v => v.GetSeriesFolder(It.IsAny<Series>(), null), Times.Never());
|
.Verify(v => v.GetSeriesFolder(It.IsAny<Series>(), null), Times.Never());
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2 && s.Seasons.Single(season => season.SeasonNumber == 2).Monitored == true)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2 && s.Seasons.Single(season => season.SeasonNumber == 2).Monitored == true), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2 && s.Seasons.Single(season => season.SeasonNumber == 0).Monitored == false)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2 && s.Seasons.Single(season => season.SeasonNumber == 0).Monitored == false), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -92,7 +92,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvRageId == newSeriesInfo.TvRageId)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvRageId == newSeriesInfo.TvRageId), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvMazeId == newSeriesInfo.TvMazeId)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvMazeId == newSeriesInfo.TvMazeId), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -115,7 +115,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
.Verify(v => v.UpdateSeries(It.IsAny<Series>(), It.IsAny<bool>()), Times.Never());
|
||||||
|
|
||||||
ExceptionVerification.ExpectedErrors(1);
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvdbId == newSeriesInfo.TvdbId)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvdbId == newSeriesInfo.TvdbId), It.IsAny<bool>()));
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
ExceptionVerification.ExpectedWarns(1);
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2), It.IsAny<bool>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -177,7 +177,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||||
|
|
||||||
Mocker.GetMock<ISeriesService>()
|
Mocker.GetMock<ISeriesService>()
|
||||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2)));
|
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2), It.IsAny<bool>()));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
<package id="FluentMigrator" version="1.6.2" targetFramework="net40" />
|
<package id="FluentMigrator" version="1.6.2" targetFramework="net40" />
|
||||||
<package id="FluentMigrator.Runner" version="1.6.2" targetFramework="net40" />
|
<package id="FluentMigrator.Runner" version="1.6.2" targetFramework="net40" />
|
||||||
<package id="FluentValidation" version="6.2.1.0" targetFramework="net40" />
|
<package id="FluentValidation" version="6.2.1.0" targetFramework="net40" />
|
||||||
<package id="Moq" version="4.0.10827" />
|
<package id="Moq" version="4.0.10827" targetFramework="net40" />
|
||||||
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
|
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
|
||||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
|
||||||
<package id="NLog" version="4.4.3" targetFramework="net40" />
|
<package id="NLog" version="4.4.12" targetFramework="net40" />
|
||||||
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
<package id="NUnit" version="3.6.0" targetFramework="net40" />
|
||||||
<package id="Prowlin" version="0.9.4456.26422" targetFramework="net40" />
|
<package id="Prowlin" version="0.9.4456.26422" targetFramework="net40" />
|
||||||
<package id="Unity" version="2.1.505.2" targetFramework="net40" />
|
<package id="Unity" version="2.1.505.2" targetFramework="net40" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace NzbDrone.Core.Backup
|
|||||||
{
|
{
|
||||||
public class Backup
|
public class Backup
|
||||||
{
|
{
|
||||||
public string Path { get; set; }
|
public string Name { get; set; }
|
||||||
public BackupType Type { get; set; }
|
public BackupType Type { get; set; }
|
||||||
public DateTime Time { get; set; }
|
public DateTime Time { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,18 @@ namespace NzbDrone.Core.Backup
|
|||||||
{
|
{
|
||||||
public class BackupCommand : Command
|
public class BackupCommand : Command
|
||||||
{
|
{
|
||||||
public BackupType Type { get; set; }
|
public BackupType Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Trigger == CommandTrigger.Scheduled)
|
||||||
|
{
|
||||||
|
return BackupType.Scheduled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BackupType.Manual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool SendUpdatesToClient => true;
|
public override bool SendUpdatesToClient => true;
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ namespace NzbDrone.Core.Backup
|
|||||||
{
|
{
|
||||||
backups.AddRange(GetBackupFiles(folder).Select(b => new Backup
|
backups.AddRange(GetBackupFiles(folder).Select(b => new Backup
|
||||||
{
|
{
|
||||||
Path = Path.GetFileName(b),
|
Name = Path.GetFileName(b),
|
||||||
Type = backupType,
|
Type = backupType,
|
||||||
Time = _diskProvider.FileGetLastWrite(b)
|
Time = _diskProvider.FileGetLastWrite(b)
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(118)]
|
||||||
|
public class add_history_eventType_index : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Create.Index().OnTable("History").OnColumn("EventType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,7 +81,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||||||
|
|
||||||
var episodeIds = subject.Episodes.Select(e => e.Id);
|
var episodeIds = subject.Episodes.Select(e => e.Id);
|
||||||
|
|
||||||
var oldest = _pendingReleaseService.OldestPendingRelease(subject.Series.Id, episodeIds);
|
var oldest = _pendingReleaseService.OldestPendingRelease(subject.Series.Id, episodeIds.ToArray());
|
||||||
|
|
||||||
if (oldest != null && oldest.Release.AgeMinutes > delay)
|
if (oldest != null && oldest.Release.AgeMinutes > delay)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
@@ -22,6 +23,8 @@ namespace NzbDrone.Core.DiskSpace
|
|||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
private static readonly Regex _regexSpecialDrive = new Regex("^/var/lib/(docker|rancher|kubelet)(/|$)|^/boot(/|$)|/docker(/var)?/aufs(/|$)", RegexOptions.Compiled);
|
||||||
|
|
||||||
public DiskSpaceService(ISeriesService seriesService, IConfigService configService, IDiskProvider diskProvider, Logger logger)
|
public DiskSpaceService(ISeriesService seriesService, IConfigService configService, IDiskProvider diskProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
@@ -32,37 +35,37 @@ namespace NzbDrone.Core.DiskSpace
|
|||||||
|
|
||||||
public List<DiskSpace> GetFreeSpace()
|
public List<DiskSpace> GetFreeSpace()
|
||||||
{
|
{
|
||||||
var diskSpace = new List<DiskSpace>();
|
var importantRootFolders = GetSeriesRootPaths().Concat(GetDroneFactoryRootPaths()).Distinct().ToList();
|
||||||
diskSpace.AddRange(GetSeriesFreeSpace());
|
|
||||||
diskSpace.AddRange(GetDroneFactoryFreeSpace());
|
|
||||||
diskSpace.AddRange(GetFixedDisksFreeSpace());
|
|
||||||
|
|
||||||
return diskSpace.DistinctBy(d => d.Path).ToList();
|
var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList();
|
||||||
|
|
||||||
|
var diskSpace = GetDiskSpace(importantRootFolders).Concat(GetDiskSpace(optionalRootFolders, true)).ToList();
|
||||||
|
|
||||||
|
return diskSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetSeriesFreeSpace()
|
private IEnumerable<string> GetSeriesRootPaths()
|
||||||
{
|
{
|
||||||
var seriesRootPaths = _seriesService.GetAllSeries()
|
return _seriesService.GetAllSeries()
|
||||||
.Where(s => _diskProvider.FolderExists(s.Path))
|
.Where(s => _diskProvider.FolderExists(s.Path))
|
||||||
.Select(s => _diskProvider.GetPathRoot(s.Path))
|
.Select(s => _diskProvider.GetPathRoot(s.Path))
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
return GetDiskSpace(seriesRootPaths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetDroneFactoryFreeSpace()
|
private IEnumerable<string> GetDroneFactoryRootPaths()
|
||||||
{
|
{
|
||||||
if (_configService.DownloadedEpisodesFolder.IsNotNullOrWhiteSpace() && _diskProvider.FolderExists(_configService.DownloadedEpisodesFolder))
|
if (_configService.DownloadedEpisodesFolder.IsNotNullOrWhiteSpace() && _diskProvider.FolderExists(_configService.DownloadedEpisodesFolder))
|
||||||
{
|
{
|
||||||
return GetDiskSpace(new[] { _diskProvider.GetPathRoot(_configService.DownloadedEpisodesFolder) });
|
yield return _configService.DownloadedEpisodesFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new List<DiskSpace>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetFixedDisksFreeSpace()
|
private IEnumerable<string> GetFixedDisksRootPaths()
|
||||||
{
|
{
|
||||||
return GetDiskSpace(_diskProvider.GetMounts().Where(d => d.DriveType == DriveType.Fixed).Select(d => d.RootDirectory), true);
|
return _diskProvider.GetMounts()
|
||||||
|
.Where(d => d.DriveType == DriveType.Fixed)
|
||||||
|
.Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory))
|
||||||
|
.Select(d => d.RootDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetDiskSpace(IEnumerable<string> paths, bool suppressWarnings = false)
|
private IEnumerable<DiskSpace> GetDiskSpace(IEnumerable<string> paths, bool suppressWarnings = false)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
@@ -109,7 +109,17 @@ namespace NzbDrone.Core.Download.Clients.Deluge
|
|||||||
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath));
|
var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath));
|
||||||
item.OutputPath = outputPath + torrent.Name;
|
item.OutputPath = outputPath + torrent.Name;
|
||||||
item.RemainingSize = torrent.Size - torrent.BytesDownloaded;
|
item.RemainingSize = torrent.Size - torrent.BytesDownloaded;
|
||||||
item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta);
|
||||||
|
}
|
||||||
|
catch (OverflowException ex)
|
||||||
|
{
|
||||||
|
_logger.Debug(ex, "ETA for {0} is too long: {1}", torrent.Name, torrent.Eta);
|
||||||
|
item.RemainingTime = TimeSpan.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
item.TotalSize = torrent.Size;
|
item.TotalSize = torrent.Size;
|
||||||
|
|
||||||
if (torrent.State == DelugeTorrentStatus.Error)
|
if (torrent.State == DelugeTorrentStatus.Error)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
@@ -48,6 +48,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
|
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetInitialState(hash.ToLower());
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +84,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
_logger.Warn(ex, "Failed to set the torrent priority for {0}.", filename);
|
_logger.Warn(ex, "Failed to set the torrent priority for {0}.", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetInitialState(hash);
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +124,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
{
|
{
|
||||||
case "error": // some error occurred, applies to paused torrents
|
case "error": // some error occurred, applies to paused torrents
|
||||||
item.Status = DownloadItemStatus.Failed;
|
item.Status = DownloadItemStatus.Failed;
|
||||||
item.Message = "QBittorrent is reporting an error";
|
item.Message = "qBittorrent is reporting an error";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "pausedDL": // torrent is paused and has NOT finished downloading
|
case "pausedDL": // torrent is paused and has NOT finished downloading
|
||||||
@@ -222,7 +226,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
var config = _proxy.GetConfig(Settings);
|
var config = _proxy.GetConfig(Settings);
|
||||||
if (config.MaxRatioEnabled && config.RemoveOnMaxRatio)
|
if (config.MaxRatioEnabled && config.RemoveOnMaxRatio)
|
||||||
{
|
{
|
||||||
return new NzbDroneValidationFailure(String.Empty, "QBittorrent is configured to remove torrents when they reach their Share Ratio Limit")
|
return new NzbDroneValidationFailure(String.Empty, "qBittorrent is configured to remove torrents when they reach their Share Ratio Limit")
|
||||||
{
|
{
|
||||||
DetailedDescription = "Sonarr will be unable to perform Completed Download Handling as configured. You can fix this in qBittorrent ('Tools -> Options...' in the menu) by changing 'Options -> BitTorrent -> Share Ratio Limiting' from 'Remove them' to 'Pause them'."
|
DetailedDescription = "Sonarr will be unable to perform Completed Download Handling as configured. You can fix this in qBittorrent ('Tools -> Options...' in the menu) by changing 'Options -> BitTorrent -> Share Ratio Limiting' from 'Remove them' to 'Pause them'."
|
||||||
};
|
};
|
||||||
@@ -306,5 +310,28 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetInitialState(string hash)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch ((QBittorrentState)Settings.InitialState)
|
||||||
|
{
|
||||||
|
case QBittorrentState.ForceStart:
|
||||||
|
_proxy.SetForceStart(hash, true, Settings);
|
||||||
|
break;
|
||||||
|
case QBittorrentState.Start:
|
||||||
|
_proxy.ResumeTorrent(hash, Settings);
|
||||||
|
break;
|
||||||
|
case QBittorrentState.Pause:
|
||||||
|
_proxy.PauseTorrent(hash, Settings);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warn(ex, "Failed to set inital state for {0}.", hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using NLog;
|
using NLog;
|
||||||
@@ -23,6 +23,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
void RemoveTorrent(string hash, Boolean removeData, QBittorrentSettings settings);
|
void RemoveTorrent(string hash, Boolean removeData, QBittorrentSettings settings);
|
||||||
void SetTorrentLabel(string hash, string label, QBittorrentSettings settings);
|
void SetTorrentLabel(string hash, string label, QBittorrentSettings settings);
|
||||||
void MoveTorrentToTopInQueue(string hash, QBittorrentSettings settings);
|
void MoveTorrentToTopInQueue(string hash, QBittorrentSettings settings);
|
||||||
|
void PauseTorrent(string hash, QBittorrentSettings settings);
|
||||||
|
void ResumeTorrent(string hash, QBittorrentSettings settings);
|
||||||
|
void SetForceStart(string hash, bool enabled, QBittorrentSettings settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class QBittorrentProxy : IQBittorrentProxy
|
public class QBittorrentProxy : IQBittorrentProxy
|
||||||
@@ -117,7 +120,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
}
|
}
|
||||||
catch(DownloadClientException ex)
|
catch(DownloadClientException ex)
|
||||||
{
|
{
|
||||||
// if setCategory fails due to method not being found, then try older setLabel command for qbittorent < v.3.3.5
|
// if setCategory fails due to method not being found, then try older setLabel command for qBittorrent < v.3.3.5
|
||||||
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
|
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
|
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
|
||||||
@@ -154,6 +157,34 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PauseTorrent(string hash, QBittorrentSettings settings)
|
||||||
|
{
|
||||||
|
var request = BuildRequest(settings).Resource("/command/pause")
|
||||||
|
.Post()
|
||||||
|
.AddFormParameter("hash", hash);
|
||||||
|
|
||||||
|
ProcessRequest(request, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResumeTorrent(string hash, QBittorrentSettings settings)
|
||||||
|
{
|
||||||
|
var request = BuildRequest(settings).Resource("/command/resume")
|
||||||
|
.Post()
|
||||||
|
.AddFormParameter("hash", hash);
|
||||||
|
|
||||||
|
ProcessRequest(request, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
|
||||||
|
{
|
||||||
|
var request = BuildRequest(settings).Resource("/command/setForceStart")
|
||||||
|
.Post()
|
||||||
|
.AddFormParameter("hashes", hash)
|
||||||
|
.AddFormParameter("value", enabled ? "true": "false");
|
||||||
|
|
||||||
|
ProcessRequest(request, settings);
|
||||||
|
}
|
||||||
|
|
||||||
private HttpRequestBuilder BuildRequest(QBittorrentSettings settings)
|
private HttpRequestBuilder BuildRequest(QBittorrentSettings settings)
|
||||||
{
|
{
|
||||||
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port);
|
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port);
|
||||||
@@ -197,12 +228,12 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new DownloadClientException("Failed to connect to qBitTorrent, check your settings.", ex);
|
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (WebException ex)
|
catch (WebException ex)
|
||||||
{
|
{
|
||||||
throw new DownloadClientException("Failed to connect to qBitTorrent, please check your settings.", ex);
|
throw new DownloadClientException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.Content;
|
return response.Content;
|
||||||
@@ -239,23 +270,23 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
_logger.Debug("qbitTorrent authentication failed.");
|
_logger.Debug("qbitTorrent authentication failed.");
|
||||||
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
|
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
|
||||||
{
|
{
|
||||||
throw new DownloadClientAuthenticationException("Failed to authenticate with qbitTorrent.", ex);
|
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new DownloadClientException("Failed to connect to qBitTorrent, please check your settings.", ex);
|
throw new DownloadClientException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
catch (WebException ex)
|
catch (WebException ex)
|
||||||
{
|
{
|
||||||
throw new DownloadClientUnavailableException("Failed to connect to qBitTorrent, please check your settings.", ex);
|
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.Content != "Ok.") // returns "Fails." on bad login
|
if (response.Content != "Ok.") // returns "Fails." on bad login
|
||||||
{
|
{
|
||||||
_logger.Debug("qbitTorrent authentication failed.");
|
_logger.Debug("qbitTorrent authentication failed.");
|
||||||
throw new DownloadClientAuthenticationException("Failed to authenticate with qbitTorrent.");
|
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("qbitTorrent authentication succeeded.");
|
_logger.Debug("qBittorrent authentication succeeded.");
|
||||||
|
|
||||||
cookies = response.GetCookies();
|
cookies = response.GetCookies();
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
public QBittorrentSettings()
|
public QBittorrentSettings()
|
||||||
{
|
{
|
||||||
Host = "localhost";
|
Host = "localhost";
|
||||||
Port = 9091;
|
Port = 8080;
|
||||||
TvCategory = "tv-sonarr";
|
TvCategory = "tv-sonarr";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,10 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(QBittorrentPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
|
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(QBittorrentPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
|
||||||
public int OlderTvPriority { get; set; }
|
public int OlderTvPriority { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use a secure connection. See Options -> Web UI -> 'Use HTTPS instead of HTTP' in qBittorrent.")]
|
[FieldDefinition(7, Label = "Initial State", Type = FieldType.Select, SelectOptions = typeof(QBittorrentState), HelpText = "Initial state for torrents added to qBittorrent")]
|
||||||
|
public int InitialState { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use a secure connection. See Options -> Web UI -> 'Use HTTPS instead of HTTP' in qBittorrent.")]
|
||||||
public bool UseSsl { get; set; }
|
public bool UseSsl { get; set; }
|
||||||
|
|
||||||
public NzbDroneValidationResult Validate()
|
public NzbDroneValidationResult Validate()
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||||
|
{
|
||||||
|
public enum QBittorrentState
|
||||||
|
{
|
||||||
|
Start = 0,
|
||||||
|
ForceStart = 1,
|
||||||
|
Pause = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -81,7 +81,8 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
|
|||||||
queueItem.CanBeRemoved = true;
|
queueItem.CanBeRemoved = true;
|
||||||
queueItem.CanMoveFiles = true;
|
queueItem.CanMoveFiles = true;
|
||||||
|
|
||||||
if (sabQueue.Paused || sabQueueItem.Status == SabnzbdDownloadStatus.Paused)
|
if ((sabQueue.Paused && sabQueueItem.Priority != SabnzbdPriority.Force) ||
|
||||||
|
sabQueueItem.Status == SabnzbdDownloadStatus.Paused)
|
||||||
{
|
{
|
||||||
queueItem.Status = DownloadItemStatus.Paused;
|
queueItem.Status = DownloadItemStatus.Paused;
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
|||||||
_proxy.MoveTorrentToTopInQueue(hash, Settings);
|
_proxy.MoveTorrentToTopInQueue(hash, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_proxy.SetState(hash, (UTorrentState)Settings.IntialState, Settings);
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +67,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
|||||||
_proxy.MoveTorrentToTopInQueue(hash, Settings);
|
_proxy.MoveTorrentToTopInQueue(hash, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_proxy.SetState(hash, (UTorrentState)Settings.IntialState, Settings);
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
|||||||
void RemoveTorrent(string hash, bool removeData, UTorrentSettings settings);
|
void RemoveTorrent(string hash, bool removeData, UTorrentSettings settings);
|
||||||
void SetTorrentLabel(string hash, string label, UTorrentSettings settings);
|
void SetTorrentLabel(string hash, string label, UTorrentSettings settings);
|
||||||
void MoveTorrentToTopInQueue(string hash, UTorrentSettings settings);
|
void MoveTorrentToTopInQueue(string hash, UTorrentSettings settings);
|
||||||
|
void SetState(string hash, UTorrentState state, UTorrentSettings settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UTorrentProxy : IUTorrentProxy
|
public class UTorrentProxy : IUTorrentProxy
|
||||||
@@ -157,6 +158,15 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
|||||||
ProcessRequest(requestBuilder, settings);
|
ProcessRequest(requestBuilder, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetState(string hash, UTorrentState state, UTorrentSettings settings)
|
||||||
|
{
|
||||||
|
var requestBuilder = BuildRequest(settings)
|
||||||
|
.AddQueryParam("action", state.ToString().ToLowerInvariant())
|
||||||
|
.AddQueryParam("hash", hash);
|
||||||
|
|
||||||
|
ProcessRequest(requestBuilder, settings);
|
||||||
|
}
|
||||||
|
|
||||||
private HttpRequestBuilder BuildRequest(UTorrentSettings settings)
|
private HttpRequestBuilder BuildRequest(UTorrentSettings settings)
|
||||||
{
|
{
|
||||||
var requestBuilder = new HttpRequestBuilder(false, settings.Host, settings.Port)
|
var requestBuilder = new HttpRequestBuilder(false, settings.Host, settings.Port)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using NzbDrone.Core.Annotations;
|
using NzbDrone.Core.Annotations;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
@@ -22,7 +22,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
|||||||
public UTorrentSettings()
|
public UTorrentSettings()
|
||||||
{
|
{
|
||||||
Host = "localhost";
|
Host = "localhost";
|
||||||
Port = 9091;
|
Port = 8080;
|
||||||
TvCategory = "tv-sonarr";
|
TvCategory = "tv-sonarr";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +47,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
|
|||||||
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
|
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
|
||||||
public int OlderTvPriority { get; set; }
|
public int OlderTvPriority { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(7, Label = "Initial State", Type = FieldType.Select, SelectOptions = typeof(UTorrentState), HelpText = "Initial state for torrents added to uTorrent")]
|
||||||
|
public int IntialState { get; set; }
|
||||||
|
|
||||||
public NzbDroneValidationResult Validate()
|
public NzbDroneValidationResult Validate()
|
||||||
{
|
{
|
||||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
|
|||||||
10
src/NzbDrone.Core/Download/Clients/uTorrent/UtorrentState.cs
Normal file
10
src/NzbDrone.Core/Download/Clients/uTorrent/UtorrentState.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace NzbDrone.Core.Download.Clients.UTorrent
|
||||||
|
{
|
||||||
|
public enum UTorrentState
|
||||||
|
{
|
||||||
|
Start = 0,
|
||||||
|
ForceStart = 1,
|
||||||
|
Pause = 2,
|
||||||
|
Stop = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnsureThat;
|
using NzbDrone.Common.EnsureThat;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Common.Instrumentation.Extensions;
|
using NzbDrone.Common.Instrumentation.Extensions;
|
||||||
using NzbDrone.Common.TPL;
|
using NzbDrone.Common.TPL;
|
||||||
|
using NzbDrone.Core.Download.Clients;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
@@ -52,8 +53,12 @@ namespace NzbDrone.Core.Download
|
|||||||
|
|
||||||
if (downloadClient == null)
|
if (downloadClient == null)
|
||||||
{
|
{
|
||||||
_logger.Warn("{0} Download client isn't configured yet.", remoteEpisode.Release.DownloadProtocol);
|
throw new DownloadClientUnavailableException($"{remoteEpisode.Release.DownloadProtocol} Download client isn't configured yet");
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
if (_downloadClientStatusService.IsDisabled(downloadClient.Definition.Id))
|
||||||
|
{
|
||||||
|
throw new DownloadClientUnavailableException($"{downloadClient.Name} is disabled due to recent failues");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit grabs to 2 per second.
|
// Limit grabs to 2 per second.
|
||||||
@@ -70,6 +75,11 @@ namespace NzbDrone.Core.Download
|
|||||||
_downloadClientStatusService.RecordSuccess(downloadClient.Definition.Id);
|
_downloadClientStatusService.RecordSuccess(downloadClient.Definition.Id);
|
||||||
_indexerStatusService.RecordSuccess(remoteEpisode.Release.IndexerId);
|
_indexerStatusService.RecordSuccess(remoteEpisode.Release.IndexerId);
|
||||||
}
|
}
|
||||||
|
catch (ReleaseUnavailableException)
|
||||||
|
{
|
||||||
|
_logger.Trace("Release {0} no longer available on indexer.", remoteEpisode);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (ReleaseDownloadException ex)
|
catch (ReleaseDownloadException ex)
|
||||||
{
|
{
|
||||||
var http429 = ex.InnerException as TooManyRequestsException;
|
var http429 = ex.InnerException as TooManyRequestsException;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
{
|
{
|
||||||
void DeleteBySeriesId(int seriesId);
|
void DeleteBySeriesId(int seriesId);
|
||||||
List<PendingRelease> AllBySeriesId(int seriesId);
|
List<PendingRelease> AllBySeriesId(int seriesId);
|
||||||
|
List<PendingRelease> WithoutFallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PendingReleaseRepository : BasicRepository<PendingRelease>, IPendingReleaseRepository
|
public class PendingReleaseRepository : BasicRepository<PendingRelease>, IPendingReleaseRepository
|
||||||
@@ -26,5 +27,10 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
{
|
{
|
||||||
return Query.Where(p => p.SeriesId == seriesId);
|
return Query.Where(p => p.SeriesId == seriesId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<PendingRelease> WithoutFallback()
|
||||||
|
{
|
||||||
|
return Query.Where(p => p.Reason != PendingReleaseReason.Fallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,13 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
public interface IPendingReleaseService
|
public interface IPendingReleaseService
|
||||||
{
|
{
|
||||||
void Add(DownloadDecision decision, PendingReleaseReason reason);
|
void Add(DownloadDecision decision, PendingReleaseReason reason);
|
||||||
|
void AddMany(List<Tuple<DownloadDecision, PendingReleaseReason>> decisions);
|
||||||
List<ReleaseInfo> GetPending();
|
List<ReleaseInfo> GetPending();
|
||||||
List<RemoteEpisode> GetPendingRemoteEpisodes(int seriesId);
|
List<RemoteEpisode> GetPendingRemoteEpisodes(int seriesId);
|
||||||
List<Queue.Queue> GetPendingQueue();
|
List<Queue.Queue> GetPendingQueue();
|
||||||
Queue.Queue FindPendingQueueItem(int queueId);
|
Queue.Queue FindPendingQueueItem(int queueId);
|
||||||
void RemovePendingQueueItems(int queueId);
|
void RemovePendingQueueItems(int queueId);
|
||||||
RemoteEpisode OldestPendingRelease(int seriesId, IEnumerable<int> episodeIds);
|
RemoteEpisode OldestPendingRelease(int seriesId, int[] episodeIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PendingReleaseService : IPendingReleaseService,
|
public class PendingReleaseService : IPendingReleaseService,
|
||||||
@@ -68,8 +69,27 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
|
|
||||||
public void Add(DownloadDecision decision, PendingReleaseReason reason)
|
public void Add(DownloadDecision decision, PendingReleaseReason reason)
|
||||||
{
|
{
|
||||||
var alreadyPending = GetPendingReleases();
|
var alreadyPending = _repository.AllBySeriesId(decision.RemoteEpisode.Series.Id);
|
||||||
|
|
||||||
|
alreadyPending = IncludeRemoteEpisodes(alreadyPending);
|
||||||
|
|
||||||
|
Add(alreadyPending, decision, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddMany(List<Tuple<DownloadDecision, PendingReleaseReason>> decisions)
|
||||||
|
{
|
||||||
|
var alreadyPending = decisions.Select(v => v.Item1.RemoteEpisode.Series.Id).Distinct().SelectMany(_repository.AllBySeriesId).ToList();
|
||||||
|
|
||||||
|
alreadyPending = IncludeRemoteEpisodes(alreadyPending);
|
||||||
|
|
||||||
|
foreach (var pair in decisions)
|
||||||
|
{
|
||||||
|
Add(alreadyPending, pair.Item1, pair.Item2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Add(List<PendingRelease> alreadyPending, DownloadDecision decision, PendingReleaseReason reason)
|
||||||
|
{
|
||||||
var episodeIds = decision.RemoteEpisode.Episodes.Select(e => e.Id);
|
var episodeIds = decision.RemoteEpisode.Episodes.Select(e => e.Id);
|
||||||
|
|
||||||
var existingReports = alreadyPending.Where(r => r.RemoteEpisode.Episodes.Select(e => e.Id)
|
var existingReports = alreadyPending.Where(r => r.RemoteEpisode.Episodes.Select(e => e.Id)
|
||||||
@@ -80,24 +100,31 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
|
|
||||||
if (matchingReports.Any())
|
if (matchingReports.Any())
|
||||||
{
|
{
|
||||||
var sameReason = true;
|
var matchingReport = matchingReports.First();
|
||||||
|
|
||||||
foreach (var matchingReport in matchingReports)
|
if (matchingReport.Reason != reason)
|
||||||
{
|
{
|
||||||
if (matchingReport.Reason != reason)
|
_logger.Debug("The release {0} is already pending with reason {1}, changing to {2}", decision.RemoteEpisode, matchingReport.Reason, reason);
|
||||||
|
matchingReport.Reason = reason;
|
||||||
|
_repository.Update(matchingReport);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug("The release {0} is already pending with reason {1}, not adding again", decision.RemoteEpisode, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingReports.Count() > 1)
|
||||||
|
{
|
||||||
|
_logger.Debug("The release {0} had {1} duplicate pending, removing duplicates.", decision.RemoteEpisode, matchingReports.Count() - 1);
|
||||||
|
|
||||||
|
foreach (var duplicate in matchingReports.Skip(1))
|
||||||
{
|
{
|
||||||
_logger.Debug("The release {0} is already pending with reason {1}, changing to {2}", decision.RemoteEpisode, matchingReport.Reason, reason);
|
_repository.Delete(duplicate.Id);
|
||||||
matchingReport.Reason = reason;
|
alreadyPending.Remove(duplicate);
|
||||||
_repository.Update(matchingReport);
|
|
||||||
sameReason = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sameReason)
|
return;
|
||||||
{
|
|
||||||
_logger.Debug("The release {0} is already pending with reason {1}, not adding again", decision.RemoteEpisode, reason);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Adding release {0} to pending releases with reason {1}", decision.RemoteEpisode, reason);
|
_logger.Debug("Adding release {0} to pending releases with reason {1}", decision.RemoteEpisode, reason);
|
||||||
@@ -125,7 +152,7 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
|
|
||||||
public List<RemoteEpisode> GetPendingRemoteEpisodes(int seriesId)
|
public List<RemoteEpisode> GetPendingRemoteEpisodes(int seriesId)
|
||||||
{
|
{
|
||||||
return _repository.AllBySeriesId(seriesId).Select(GetRemoteEpisode).ToList();
|
return IncludeRemoteEpisodes(_repository.AllBySeriesId(seriesId)).Select(v => v.RemoteEpisode).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Queue.Queue> GetPendingQueue()
|
public List<Queue.Queue> GetPendingQueue()
|
||||||
@@ -134,7 +161,8 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
|
|
||||||
var nextRssSync = new Lazy<DateTime>(() => _taskManager.GetNextExecution(typeof(RssSyncCommand)));
|
var nextRssSync = new Lazy<DateTime>(() => _taskManager.GetNextExecution(typeof(RssSyncCommand)));
|
||||||
|
|
||||||
foreach (var pendingRelease in GetPendingReleases().Where(p => p.Reason != PendingReleaseReason.Fallback))
|
var pendingReleases = IncludeRemoteEpisodes(_repository.WithoutFallback());
|
||||||
|
foreach (var pendingRelease in pendingReleases)
|
||||||
{
|
{
|
||||||
foreach (var episode in pendingRelease.RemoteEpisode.Episodes)
|
foreach (var episode in pendingRelease.RemoteEpisode.Episodes)
|
||||||
{
|
{
|
||||||
@@ -206,24 +234,48 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
_repository.DeleteMany(releasesToRemove.Select(c => c.Id));
|
_repository.DeleteMany(releasesToRemove.Select(c => c.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteEpisode OldestPendingRelease(int seriesId, IEnumerable<int> episodeIds)
|
public RemoteEpisode OldestPendingRelease(int seriesId, int[] episodeIds)
|
||||||
{
|
{
|
||||||
return GetPendingRemoteEpisodes(seriesId).Where(r => r.Episodes.Select(e => e.Id).Intersect(episodeIds).Any())
|
var seriesReleases = GetPendingReleases(seriesId);
|
||||||
.OrderByDescending(p => p.Release.AgeHours)
|
|
||||||
.FirstOrDefault();
|
return seriesReleases.Select(r => r.RemoteEpisode)
|
||||||
|
.Where(r => r.Episodes.Select(e => e.Id).Intersect(episodeIds).Any())
|
||||||
|
.OrderByDescending(p => p.Release.AgeHours)
|
||||||
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PendingRelease> GetPendingReleases()
|
private List<PendingRelease> GetPendingReleases()
|
||||||
|
{
|
||||||
|
return IncludeRemoteEpisodes(_repository.All().ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PendingRelease> GetPendingReleases(int seriesId)
|
||||||
|
{
|
||||||
|
return IncludeRemoteEpisodes(_repository.AllBySeriesId(seriesId).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PendingRelease> IncludeRemoteEpisodes(List<PendingRelease> releases)
|
||||||
{
|
{
|
||||||
var result = new List<PendingRelease>();
|
var result = new List<PendingRelease>();
|
||||||
|
var seriesMap = _seriesService.GetSeries(releases.Select(v => v.SeriesId).Distinct())
|
||||||
|
.ToDictionary(v => v.Id);
|
||||||
|
|
||||||
foreach (var release in _repository.All())
|
foreach (var release in releases)
|
||||||
{
|
{
|
||||||
var remoteEpisode = GetRemoteEpisode(release);
|
var series = seriesMap.GetValueOrDefault(release.SeriesId);
|
||||||
|
|
||||||
if (remoteEpisode == null) continue;
|
// Just in case the series was removed, but wasn't cleaned up yet (housekeeper will clean it up)
|
||||||
|
if (series == null) return null;
|
||||||
|
|
||||||
release.RemoteEpisode = remoteEpisode;
|
var episodes = _parsingService.GetEpisodes(release.ParsedEpisodeInfo, series, true);
|
||||||
|
|
||||||
|
release.RemoteEpisode = new RemoteEpisode
|
||||||
|
{
|
||||||
|
Series = series,
|
||||||
|
Episodes = episodes,
|
||||||
|
ParsedEpisodeInfo = release.ParsedEpisodeInfo,
|
||||||
|
Release = release.Release
|
||||||
|
};
|
||||||
|
|
||||||
result.Add(release);
|
result.Add(release);
|
||||||
}
|
}
|
||||||
@@ -231,24 +283,6 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RemoteEpisode GetRemoteEpisode(PendingRelease release)
|
|
||||||
{
|
|
||||||
var series = _seriesService.GetSeries(release.SeriesId);
|
|
||||||
|
|
||||||
//Just in case the series was removed, but wasn't cleaned up yet (housekeeper will clean it up)
|
|
||||||
if (series == null) return null;
|
|
||||||
|
|
||||||
var episodes = _parsingService.GetEpisodes(release.ParsedEpisodeInfo, series, true);
|
|
||||||
|
|
||||||
return new RemoteEpisode
|
|
||||||
{
|
|
||||||
Series = series,
|
|
||||||
Episodes = episodes,
|
|
||||||
ParsedEpisodeInfo = release.ParsedEpisodeInfo,
|
|
||||||
Release = release.Release
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Insert(DownloadDecision decision, PendingReleaseReason reason)
|
private void Insert(DownloadDecision decision, PendingReleaseReason reason)
|
||||||
{
|
{
|
||||||
_repository.Insert(new PendingRelease
|
_repository.Insert(new PendingRelease
|
||||||
@@ -288,7 +322,7 @@ namespace NzbDrone.Core.Download.Pending
|
|||||||
|
|
||||||
private void RemoveGrabbed(RemoteEpisode remoteEpisode)
|
private void RemoveGrabbed(RemoteEpisode remoteEpisode)
|
||||||
{
|
{
|
||||||
var pendingReleases = GetPendingReleases();
|
var pendingReleases = GetPendingReleases(remoteEpisode.Series.Id);
|
||||||
var episodeIds = remoteEpisode.Episodes.Select(e => e.Id);
|
var episodeIds = remoteEpisode.Episodes.Select(e => e.Id);
|
||||||
|
|
||||||
var existingReports = pendingReleases.Where(r => r.RemoteEpisode.Episodes.Select(e => e.Id)
|
var existingReports = pendingReleases.Where(r => r.RemoteEpisode.Episodes.Select(e => e.Id)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using NLog;
|
|||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.Core.Download.Clients;
|
using NzbDrone.Core.Download.Clients;
|
||||||
using NzbDrone.Core.Download.Pending;
|
using NzbDrone.Core.Download.Pending;
|
||||||
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download
|
namespace NzbDrone.Core.Download
|
||||||
@@ -40,6 +41,7 @@ namespace NzbDrone.Core.Download
|
|||||||
var grabbed = new List<DownloadDecision>();
|
var grabbed = new List<DownloadDecision>();
|
||||||
var pending = new List<DownloadDecision>();
|
var pending = new List<DownloadDecision>();
|
||||||
var failed = new List<DownloadDecision>();
|
var failed = new List<DownloadDecision>();
|
||||||
|
var rejected = decisions.Where(d => d.Rejected).ToList();
|
||||||
|
|
||||||
var usenetFailed = false;
|
var usenetFailed = false;
|
||||||
var torrentFailed = false;
|
var torrentFailed = false;
|
||||||
@@ -74,6 +76,11 @@ namespace NzbDrone.Core.Download
|
|||||||
_downloadService.DownloadReport(remoteEpisode);
|
_downloadService.DownloadReport(remoteEpisode);
|
||||||
grabbed.Add(report);
|
grabbed.Add(report);
|
||||||
}
|
}
|
||||||
|
catch (ReleaseUnavailableException)
|
||||||
|
{
|
||||||
|
_logger.Warn("Failed to download release from indexer, no longer available. " + remoteEpisode);
|
||||||
|
rejected.Add(report);
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (ex is DownloadClientUnavailableException || ex is DownloadClientAuthenticationException)
|
if (ex is DownloadClientUnavailableException || ex is DownloadClientAuthenticationException)
|
||||||
@@ -99,7 +106,7 @@ namespace NzbDrone.Core.Download
|
|||||||
|
|
||||||
pending.AddRange(ProcessFailedGrabs(grabbed, failed));
|
pending.AddRange(ProcessFailedGrabs(grabbed, failed));
|
||||||
|
|
||||||
return new ProcessedDecisions(grabbed, pending, decisions.Where(d => d.Rejected).ToList());
|
return new ProcessedDecisions(grabbed, pending, rejected);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<DownloadDecision> GetQualifiedReports(IEnumerable<DownloadDecision> decisions)
|
internal List<DownloadDecision> GetQualifiedReports(IEnumerable<DownloadDecision> decisions)
|
||||||
@@ -124,6 +131,8 @@ namespace NzbDrone.Core.Download
|
|||||||
var pending = new List<DownloadDecision>();
|
var pending = new List<DownloadDecision>();
|
||||||
var stored = new List<DownloadDecision>();
|
var stored = new List<DownloadDecision>();
|
||||||
|
|
||||||
|
var addQueue = new List<Tuple<DownloadDecision, PendingReleaseReason>>();
|
||||||
|
|
||||||
foreach (var report in failed)
|
foreach (var report in failed)
|
||||||
{
|
{
|
||||||
// If a release was already grabbed with matching episodes we should store it as a fallback
|
// If a release was already grabbed with matching episodes we should store it as a fallback
|
||||||
@@ -134,22 +143,27 @@ namespace NzbDrone.Core.Download
|
|||||||
|
|
||||||
if (IsEpisodeProcessed(grabbed, report))
|
if (IsEpisodeProcessed(grabbed, report))
|
||||||
{
|
{
|
||||||
_pendingReleaseService.Add(report, PendingReleaseReason.Fallback);
|
addQueue.Add(Tuple.Create(report, PendingReleaseReason.Fallback));
|
||||||
pending.Add(report);
|
pending.Add(report);
|
||||||
}
|
}
|
||||||
else if (IsEpisodeProcessed(stored, report))
|
else if (IsEpisodeProcessed(stored, report))
|
||||||
{
|
{
|
||||||
_pendingReleaseService.Add(report, PendingReleaseReason.Fallback);
|
addQueue.Add(Tuple.Create(report, PendingReleaseReason.Fallback));
|
||||||
pending.Add(report);
|
pending.Add(report);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pendingReleaseService.Add(report, PendingReleaseReason.DownloadClientUnavailable);
|
addQueue.Add(Tuple.Create(report, PendingReleaseReason.DownloadClientUnavailable));
|
||||||
pending.Add(report);
|
pending.Add(report);
|
||||||
stored.Add(report);
|
stored.Add(report);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addQueue.Any())
|
||||||
|
{
|
||||||
|
_pendingReleaseService.AddMany(addQueue);
|
||||||
|
}
|
||||||
|
|
||||||
return pending;
|
return pending;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Download
|
|||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_torrentFileInfoReader = torrentFileInfoReader;
|
_torrentFileInfoReader = torrentFileInfoReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||||
|
|
||||||
public virtual bool PreferTorrentFile => false;
|
public virtual bool PreferTorrentFile => false;
|
||||||
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Download
|
|||||||
{
|
{
|
||||||
magnetUrl = torrentInfo.MagnetUrl;
|
magnetUrl = torrentInfo.MagnetUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferTorrentFile)
|
if (PreferTorrentFile)
|
||||||
{
|
{
|
||||||
if (torrentUrl.IsNotNullOrWhiteSpace())
|
if (torrentUrl.IsNotNullOrWhiteSpace())
|
||||||
@@ -160,6 +160,12 @@ namespace NzbDrone.Core.Download
|
|||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException ex)
|
||||||
{
|
{
|
||||||
|
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Downloading torrent file for episode '{0}' failed since it no longer exists ({1})", remoteEpisode.Release.Title, torrentUrl);
|
||||||
|
throw new ReleaseUnavailableException(remoteEpisode.Release, "Downloading torrent failed", ex);
|
||||||
|
}
|
||||||
|
|
||||||
if ((int)ex.Response.StatusCode == 429)
|
if ((int)ex.Response.StatusCode == 429)
|
||||||
{
|
{
|
||||||
_logger.Error("API Grab Limit reached for {0}", torrentUrl);
|
_logger.Error("API Grab Limit reached for {0}", torrentUrl);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace NzbDrone.Core.Download
|
|||||||
{
|
{
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
|
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
|
||||||
|
|
||||||
protected abstract string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent);
|
protected abstract string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContent);
|
||||||
@@ -46,6 +46,12 @@ namespace NzbDrone.Core.Download
|
|||||||
}
|
}
|
||||||
catch (HttpException ex)
|
catch (HttpException ex)
|
||||||
{
|
{
|
||||||
|
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Downloading nzb file for episode '{0}' failed since it no longer exists ({1})", remoteEpisode.Release.Title, url);
|
||||||
|
throw new ReleaseUnavailableException(remoteEpisode.Release, "Downloading torrent failed", ex);
|
||||||
|
}
|
||||||
|
|
||||||
if ((int)ex.Response.StatusCode == 429)
|
if ((int)ex.Response.StatusCode == 429)
|
||||||
{
|
{
|
||||||
_logger.Error("API Grab Limit reached for {0}", url);
|
_logger.Error("API Grab Limit reached for {0}", url);
|
||||||
|
|||||||
28
src/NzbDrone.Core/Exceptions/ReleaseUnavailableException.cs
Normal file
28
src/NzbDrone.Core/Exceptions/ReleaseUnavailableException.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Exceptions
|
||||||
|
{
|
||||||
|
public class ReleaseUnavailableException : ReleaseDownloadException
|
||||||
|
{
|
||||||
|
public ReleaseUnavailableException(ReleaseInfo release, string message, params object[] args)
|
||||||
|
: base(release, message, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReleaseUnavailableException(ReleaseInfo release, string message)
|
||||||
|
: base(release, message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReleaseUnavailableException(ReleaseInfo release, string message, Exception innerException, params object[] args)
|
||||||
|
: base(release, message, innerException, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReleaseUnavailableException(ReleaseInfo release, string message, Exception innerException)
|
||||||
|
: base(release, message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Marr.Data.QGen;
|
using Marr.Data.QGen;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
@@ -16,6 +17,7 @@ namespace NzbDrone.Core.History
|
|||||||
List<History> FindByDownloadId(string downloadId);
|
List<History> FindByDownloadId(string downloadId);
|
||||||
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
||||||
void DeleteForSeries(int seriesId);
|
void DeleteForSeries(int seriesId);
|
||||||
|
List<History> Since(DateTime date, HistoryEventType? eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
||||||
@@ -76,5 +78,19 @@ namespace NzbDrone.Core.History
|
|||||||
|
|
||||||
return base.GetPagedQuery(baseQuery, pagingSpec);
|
return base.GetPagedQuery(baseQuery, pagingSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<History> Since(DateTime date, HistoryEventType? eventType)
|
||||||
|
{
|
||||||
|
var query = Query.Where(h => h.Date >= date);
|
||||||
|
|
||||||
|
if (eventType.HasValue)
|
||||||
|
{
|
||||||
|
query.AndWhere(h => h.EventType == eventType);
|
||||||
|
}
|
||||||
|
|
||||||
|
query.OrderBy(h => h.Date);
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -25,6 +25,7 @@ namespace NzbDrone.Core.History
|
|||||||
History Get(int historyId);
|
History Get(int historyId);
|
||||||
List<History> Find(string downloadId, HistoryEventType eventType);
|
List<History> Find(string downloadId, HistoryEventType eventType);
|
||||||
List<History> FindByDownloadId(string downloadId);
|
List<History> FindByDownloadId(string downloadId);
|
||||||
|
List<History> Since(DateTime date, HistoryEventType? eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HistoryService : IHistoryService,
|
public class HistoryService : IHistoryService,
|
||||||
@@ -290,5 +291,10 @@ namespace NzbDrone.Core.History
|
|||||||
{
|
{
|
||||||
_historyRepository.DeleteForSeries(message.Series.Id);
|
_historyRepository.DeleteForSeries(message.Series.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<History> Since(DateTime date, HistoryEventType? eventType)
|
||||||
|
{
|
||||||
|
return _historyRepository.Since(date, eventType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using NzbDrone.Core.Download;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
public class FixFutureDownloadClientStatusTimes : FixFutureProviderStatusTimes<DownloadClientStatus>, IHousekeepingTask
|
||||||
|
{
|
||||||
|
public FixFutureDownloadClientStatusTimes(IDownloadClientStatusRepository downloadClientStatusRepository)
|
||||||
|
: base(downloadClientStatusRepository)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
public class FixFutureIndexerStatusTimes : FixFutureProviderStatusTimes<IndexerStatus>, IHousekeepingTask
|
||||||
|
{
|
||||||
|
public FixFutureIndexerStatusTimes(IIndexerStatusRepository indexerStatusRepository)
|
||||||
|
: base(indexerStatusRepository)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.ThingiProvider.Status;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
public abstract class FixFutureProviderStatusTimes<TModel> where TModel : ProviderStatusBase, new()
|
||||||
|
{
|
||||||
|
private readonly IProviderStatusRepository<TModel> _repo;
|
||||||
|
|
||||||
|
protected FixFutureProviderStatusTimes(IProviderStatusRepository<TModel> repo)
|
||||||
|
{
|
||||||
|
_repo = repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean()
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var statuses = _repo.All().ToList();
|
||||||
|
var toUpdate = new List<TModel>();
|
||||||
|
|
||||||
|
foreach (var status in statuses)
|
||||||
|
{
|
||||||
|
var updated = false;
|
||||||
|
var escalationDelay = EscalationBackOff.Periods[status.EscalationLevel];
|
||||||
|
var disabledTill = now.AddMinutes(escalationDelay);
|
||||||
|
|
||||||
|
if (status.DisabledTill > disabledTill)
|
||||||
|
{
|
||||||
|
status.DisabledTill = disabledTill;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.InitialFailure > now)
|
||||||
|
{
|
||||||
|
status.InitialFailure = now;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.MostRecentFailure > now)
|
||||||
|
{
|
||||||
|
status.MostRecentFailure = now;
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
toUpdate.Add(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_repo.UpdateMany(toUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format("[{0} : {1:yyyy-MM-dd}", Series.Title, AirDate);
|
return string.Format("[{0} : {1:yyyy-MM-dd}]", Series.Title, AirDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user