1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-17 21:26:22 -04:00

Compare commits

...

47 Commits

Author SHA1 Message Date
FuNK3Y
002f84c58b Merge 3f26dae02b into 7756b03555 2019-05-04 20:38:40 +00:00
FuNK3Y
3f26dae02b Merge branch 'develop' into AddMetadataURL 2019-05-04 22:38:37 +02:00
Leonardo Galli
7756b03555 Fixed: a after a shortened word is not removed correctly for matching. Fixes ##3487 2019-05-02 13:18:28 +02:00
Leonardo Galli
5faaffc9c6 @cosmetic updated changelog 2019-05-02 13:05:35 +02:00
Ricardo Amaral
7a43bf3f60 Added: Tags support to NetImport (Lists) (#3127)
* Add tags support to NetImport (Lists)

* Keep indentation consistent with current code

* Initialize set of empty tags

* Add tags from list to movie

* Prevent tags used by lists from being removed
2019-05-02 12:57:40 +02:00
RhinoRhys
84fab25af7 Changed: Improved templates for h264 & h265 custom formats (#3432)
* Update CustomFormatService.cs

resolves #3419

* Update CustomFormatService.cs

* Update CustomFormatService.cs
2019-05-02 12:55:48 +02:00
jwildman16
52520e356d Changed: Logo-256.png to a transparent version so it looks better in Android notifications. (#3479) 2019-05-02 12:55:01 +02:00
Logan
cc44d022b3 Added: Radarr_Download_Id and Radarr_Download_Client to the environment (#3276)
Fixes #3232
2019-05-02 12:52:33 +02:00
Steven Crouchman
f411903e90 New: Allow CheckForFinishedDownloadInterval to be set from the UI (#3233)
* Adding CheckForFinishedDownloadInterval to config service
Changed TaskManager to use a configurable interval for CheckForFinishedDownloadCommand

* Adding new CheckForFinishedDownloadInterval to UI

Fixes #840
2019-05-02 12:51:21 +02:00
stephanrenggli
9985554dcb New: Added support for Gotify notifications (#3474)
* Added support for Gotify notifications

* Use string interpolation to build url

* Adapt changes by markus101 over at Sonarr

* Remove blank line

Fixes #3472
2019-05-02 12:49:21 +02:00
Viserius
f8c009a348 Fixed: Solve ambiguous naming (#3417) 2019-05-02 12:40:51 +02:00
Michael Poutre
da012eb6b5 Fixed: Copy to clipboard not working with calendar feed (#3495)
* Replace flash clipboard implementation with document.execute("copy")

Fixes #3486

* Replace flash clipboard implementation with document.execCommand("copy")

Resolves Radarr/Radarr#3486
2019-05-02 12:38:00 +02:00
RobinQ124274
c79578e99f Added: Remote poster and fanart references to Kodi metadata file (#2837) (#3302)
* Added: Remote poster and fanart references to Kodi metadata file (#2837)

* Added: Null checks to Remote poster and fanart references to Kodi metadata file (#2837)
2019-04-27 19:33:06 -04:00
FuNK3Y
64626b8bc3 Update XbmcMetadata.cs
Code styling again
2019-04-16 20:40:09 +02:00
FuNK3Y
85c0b95a3c Update XbmcMetadata.cs
Code styling
2019-04-16 20:36:27 +02:00
FuNK3Y
b48d9a6bac Merge branch 'develop' into AddMetadataURL 2019-04-12 22:11:33 +02:00
Leonardo Galli
961fe70cb8 @cosmetic Hopefully fixed nunit randomly failing. (updated nunit and mono) 2019-03-19 11:34:03 +01:00
Qstick
65267af512 Fixed: Edition Tags Not Showing in UI (#3389) 2019-03-19 11:08:15 +01:00
Qstick
ac387f208a Fixed: Support new feed url format IPTorrents (#573) (#3390) 2019-03-19 11:03:40 +01:00
Qstick
80304d8804 New: Support Krypton Kodi Unique Ids (#3388) 2019-03-19 11:03:20 +01:00
Qstick
cafb1a5a45 Changed: Adjust Max Slider Value for Qualities (#3393) 2019-03-19 10:59:57 +01:00
hotio
feef9b1b8d Update README.md (#3409)
Update outdated suitarr info.
2019-03-19 10:56:26 +01:00
Leonardo Galli
4aec27890c Fixed: MediaCovers Race condition which leads to fanart not being downloaded
Fixes #3350
2019-02-24 19:54:02 +01:00
Qstick
58ae4417df Fixed: Cannot Add ITA or ITALIAN custom format (#3385)
Fixes #3253
2019-02-24 18:26:20 +01:00
Qstick
6287bfd9d9 New: Nzb Validation and Nzbget/SAB URLBase (#3380) 2019-02-24 18:16:12 +01:00
Leonardo Galli
5f139c0cb6 Fixed: OsInfo for real this time. 2019-02-24 18:11:42 +01:00
Qstick
6cf257ac01 Fixed: Error in unicode cleanup code removing most non-latin characters instead of just invalid ones. (#3383) 2019-02-24 18:08:28 +01:00
Qstick
5cb5faa8a3 Fixed: Forced Subs not parsed by SubtitleLanguageRegex (#3384)
Fixes #2908
2019-02-24 18:07:48 +01:00
Leonardo Galli
a28f2fd21d Fixed: OsInfo being renamed to PlatformInfo 2019-02-24 18:06:48 +01:00
Qstick
dbf12e1fa4 Fixed: Word Boundary on Edition (#3382) 2019-02-24 18:03:42 +01:00
Václav Slavík
264629cfa5 Fixed: Mis-classification of releases as being Czech (#3378)
After the changes from PR #2948, the regex was too eager to match any
substring contain "SK", such as in "MASK". Fix by requiring word
separation around it, as was already the case with the "CZ" token.
2019-02-24 18:00:04 +01:00
Pieter Janssens
53f49f3b07 Fixed: Match MBluray releases (#3358) 2019-02-24 17:59:25 +01:00
Leonardo Galli
a26016fc08 Fixed: Mono bug causing memory leakage when http connections use gzip compression.
The bug is registered upstream, but this commit works around the problem by doing the gzip decompression separately from the http stack.

Ref #2296
2019-02-24 17:58:19 +01:00
Leonardo Galli
bd969e0bc3 Fixed: Build errors due to dotnet library. 2019-02-24 00:34:23 +01:00
hatharry
3e96fe4a72 Fixed: Emby library update (#3318)
Fixes: #3158
2019-02-18 11:12:34 +01:00
tobsen987
19299ad47f Fixed: Prevent NullRef in CustomScript on Grab for Indexer (#3323)
fixes #3313
2019-02-18 11:10:22 +01:00
Leonardo Galli
8902a3ca44 @cosmetic removed deploy 2019-02-18 11:07:51 +01:00
Leonardo Galli
4015ff08a6 @cosmetic Added Parsing Library: A dotnet library that "exports" our parsing interface. 2019-02-18 00:09:41 +01:00
Leonardo Galli
9bc50749ae Update README.md 2019-01-31 11:41:07 +01:00
Leonardo Galli
34271605c3 @cosmetic Merge pull request #3339 from hotio/patch-2
Update docker link in README
2019-01-31 11:31:26 +01:00
hotio
8272a160d2 Update docker link in README 2019-01-28 10:20:42 +01:00
FuNK3Y
abf738ffee Merge branch 'develop' into AddMetadataURL 2018-11-29 20:46:04 +01:00
Leonardo Galli
e439fb00b5 As requested
Co-Authored-By: FuNK3Y <FuNK3Y@users.noreply.github.com>
2018-11-10 16:20:39 +01:00
Leonardo Galli
e1fa7440da Update src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs
Co-Authored-By: FuNK3Y <FuNK3Y@users.noreply.github.com>
2018-11-10 16:16:50 +01:00
FuNK3Y
24cff4d6ee Update XbmcMetadata.cs
Fix typo
2018-10-14 14:24:36 +02:00
FuNK3Y
0df5cd478b Update XbmcMetadataSettings.cs
Fix typo
2018-10-14 14:24:00 +02:00
FuN_K3Y
3a55b766c3 Add imdb url, added setting, fix movie.nfo being renamed on movie rename 2018-10-14 09:59:57 +02:00
95 changed files with 1362 additions and 400 deletions

View File

@@ -1,10 +1,10 @@
FROM mono:5.8
FROM mono:5.18
RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y git ssh tar gzip ca-certificates wget zip wine wine32 wine64 libwine libwine:i386
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash -E -
RUN apt-get install -y nodejs
RUN wget https://mediaarea.net/repo/deb/repo-mediaarea_1.0-5_all.deb && dpkg -i repo-mediaarea_1.0-5_all.deb && apt-get update
RUN apt-get install -y libmediainfo-dev libmediainfo0 mediainfo
RUN wget https://mediaarea.net/repo/deb/repo-mediaarea_1.0-7_all.deb && dpkg -i repo-mediaarea_1.0-7_all.deb && apt-get update
RUN apt-get install -y libmediainfo-dev libmediainfo0v5 mediainfo
RUN npm i -g npm
RUN apt-get install -y python3-pip && pip3 install gitchangelog pystache
RUN curl -O https://dl.google.com/go/go1.10.2.linux-amd64.tar.gz && tar xvf go*.tar.gz && chown -R root:root ./go && mv go /usr/local

View File

@@ -2,7 +2,7 @@ version: 2
defaults: &defaults
docker:
- image: gallileo/radarr-cci-primary:5.8.8
- image: gallileo/radarr-cci-primary:5.8.9
environment:
BUILD_VERSION: 0.2.0
@@ -119,9 +119,9 @@ jobs:
- store_artifacts:
path: _packages
destination: artifacts
- run:
name: "Deploying"
command: chmod +x deploy.sh && ./deploy.sh
#- run:
# name: "Deploying"
# command: chmod +x deploy.sh && ./deploy.sh
- persist_to_workspace:
root: .
# Must be relative path from root

3
.gitignore vendored
View File

@@ -177,3 +177,6 @@ packages.config.md5sum
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml
# ignore node_modules symlink
node_modules
node_modules.nosync

View File

@@ -2,6 +2,43 @@
## (unreleased)
### **New features**
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Tags support to NetImport (Lists) ([#3127](https://github.com/Radarr/Radarr/issues/3127)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Improved templates for h264 & h265 custom formats ([#3432](https://github.com/Radarr/Radarr/issues/3432)) [<a href="https://github.com/RhinoRhys">RhinoRhys</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Logo-256.png to a transparent version so it looks better in Android notifications. ([#3479](https://github.com/Radarr/Radarr/issues/3479)) [<a href="https://github.com/jwildman16">jwildman16</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Radarr_Download_Id and Radarr_Download_Client to the environment ([#3276](https://github.com/Radarr/Radarr/issues/3276)) [<a href="https://github.com/Logan">Logan</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Allow CheckForFinishedDownloadInterval to be set from the UI ([#3233](https://github.com/Radarr/Radarr/issues/3233)) [<a href="https://github.com/Steven Crouchman">Steven Crouchman</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Added support for Gotify notifications ([#3474](https://github.com/Radarr/Radarr/issues/3474)) [<a href="https://github.com/stephanrenggli">stephanrenggli</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Remote poster and fanart references to Kodi metadata file ([#2837](https://github.com/Radarr/Radarr/issues/2837)) ([#3302](https://github.com/Radarr/Radarr/issues/3302)) [<a href="https://github.com/RobinQ124274">RobinQ124274</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Support Krypton Kodi Unique Ids ([#3388](https://github.com/Radarr/Radarr/issues/3388)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Adjust Max Slider Value for Qualities ([#3393](https://github.com/Radarr/Radarr/issues/3393)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) README.md ([#3409](https://github.com/Radarr/Radarr/issues/3409)) [<a href="https://github.com/hotio">hotio</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Nzb Validation and Nzbget/SAB URLBase ([#3380](https://github.com/Radarr/Radarr/issues/3380)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) README.md. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) docker link in README. [<a href="https://github.com/hotio">hotio</a>]
### **Fixes**
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Solve ambiguous naming ([#3417](https://github.com/Radarr/Radarr/issues/3417)) [<a href="https://github.com/Viserius">Viserius</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Copy to clipboard not working with calendar feed ([#3495](https://github.com/Radarr/Radarr/issues/3495)) [<a href="https://github.com/Michael Poutre">Michael Poutre</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Edition Tags Not Showing in UI ([#3389](https://github.com/Radarr/Radarr/issues/3389)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Support new feed url format IPTorrents ([#573](https://github.com/Radarr/Radarr/issues/573)) ([#3390](https://github.com/Radarr/Radarr/issues/3390)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCovers Race condition which leads to fanart not being downloaded. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Cannot Add ITA or ITALIAN custom format ([#3385](https://github.com/Radarr/Radarr/issues/3385)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OsInfo for real this time. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Error in unicode cleanup code removing most non-latin characters instead of just invalid ones. ([#3383](https://github.com/Radarr/Radarr/issues/3383)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Forced Subs not parsed by SubtitleLanguageRegex ([#3384](https://github.com/Radarr/Radarr/issues/3384)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OsInfo being renamed to PlatformInfo. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Word Boundary on Edition ([#3382](https://github.com/Radarr/Radarr/issues/3382)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Mis-classification of releases as being Czech ([#3378](https://github.com/Radarr/Radarr/issues/3378)) [<a href="https://github.com/Václav Slavík">Václav Slavík</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Match MBluray releases ([#3358](https://github.com/Radarr/Radarr/issues/3358)) [<a href="https://github.com/Pieter Janssens">Pieter Janssens</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Mono bug causing memory leakage when http connections use gzip compression. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Build errors due to dotnet library. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Emby library update ([#3318](https://github.com/Radarr/Radarr/issues/3318)) [<a href="https://github.com/hatharry">hatharry</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Prevent NullRef in CustomScript on Grab for Indexer ([#3323](https://github.com/Radarr/Radarr/issues/3323)) [<a href="https://github.com/tobsen987">tobsen987</a>]
## v0.2.0.1293 (2019-01-10)
### **New features**
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Use APIKey & APIUser for authenticating to PassThePopcorn. ([#3264](https://github.com/Radarr/Radarr/issues/3264)) [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Support for forcedUP status ([#3277](https://github.com/Radarr/Radarr/issues/3277)) [<a href="https://github.com/Swizzy">Swizzy</a>]
@@ -10,6 +47,7 @@
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Secure URLs for Links and Services ([#3219](https://github.com/Radarr/Radarr/issues/3219)) [<a href="https://github.com/Qstick">Qstick</a>]
### **Fixes**
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Hopefully fixed sqlite errors when finding by title. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Another IDisposable leak when lazy loading properties. [<a href="https://github.com/Taloth Saldono">Taloth Saldono</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCoverService tests and stupidly forgetting to open the database connection for logging. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCovers resizing potentially leaking memory when concurrently executing. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -22,13 +22,12 @@ See the [Roadmap blogpost](https://blog.radarr.video/development/update/2018/11/
## Downloads
[![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases)
[![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
Branch | develop (stable) | nightly (semi-unstable) |
---|---|---
Binary Releases | [![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases) | [![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
Docker (linuxserver.io, x86_64, arm64, armhf) | [![Docker release](https://img.shields.io/badge/linuxserver-radarr:latest-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr) | [![Docker nightly](https://img.shields.io/badge/linuxserver-radarr:nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr)
Docker (hotio, see [here](https://github.com/hotio/docker-radarr) for more information) | [![Docker release / nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://hub.docker.com/r/hotio/radarr) | [![Docker release / nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://hub.docker.com/r/hotio/radarr)
[![Docker release](https://img.shields.io/badge/docker-release-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr)
[![Docker nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/hotio/suitarr)
[![Docker armhf](https://img.shields.io/badge/docker-armhf-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr)
[![Docker aarch64](https://img.shields.io/badge/docker-aarch64-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
## Support

View File

@@ -221,9 +221,9 @@ PackageTests()
find $sourceFolder -path $testSearchPattern -exec cp -r -u -T "{}" $testPackageFolder \;
if [ $runtime = "dotnet" ] ; then
$nuget install NUnit.Runners -Version 3.2.1 -Output $testPackageFolder
$nuget install NUnit.Runners -Version 3.9.0 -Output $testPackageFolder
else
mono $nuget install NUnit.Runners -Version 3.2.1 -Output $testPackageFolder
mono $nuget install NUnit.Runners -Version 3.9.0 -Output $testPackageFolder
fi
cp $outputFolder/*.dll $testPackageFolder

102
package-lock.json generated
View File

@@ -318,6 +318,7 @@
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
"optional": true,
"requires": {
"hoek": "2.x.x"
}
@@ -495,6 +496,7 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"optional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@@ -638,7 +640,8 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"optional": true
},
"depd": {
"version": "0.4.5",
@@ -875,7 +878,8 @@
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"optional": true
},
"fancy-log": {
"version": "1.3.0",
@@ -1061,7 +1065,8 @@
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
"bundled": true,
"optional": true
},
"aproba": {
"version": "1.1.1",
@@ -1104,7 +1109,8 @@
},
"balanced-match": {
"version": "0.4.2",
"bundled": true
"bundled": true,
"optional": true
},
"bcrypt-pbkdf": {
"version": "1.0.1",
@@ -1117,6 +1123,7 @@
"block-stream": {
"version": "0.0.9",
"bundled": true,
"optional": true,
"requires": {
"inherits": "~2.0.0"
}
@@ -1124,6 +1131,7 @@
"boom": {
"version": "2.10.1",
"bundled": true,
"optional": true,
"requires": {
"hoek": "2.x.x"
}
@@ -1131,6 +1139,7 @@
"brace-expansion": {
"version": "1.1.7",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^0.4.1",
"concat-map": "0.0.1"
@@ -1138,7 +1147,8 @@
},
"buffer-shims": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"caseless": {
"version": "0.12.0",
@@ -1152,30 +1162,36 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"combined-stream": {
"version": "1.0.5",
"bundled": true,
"optional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"cryptiles": {
"version": "2.0.5",
"bundled": true,
"optional": true,
"requires": {
"boom": "2.x.x"
}
@@ -1210,7 +1226,8 @@
},
"delayed-stream": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
@@ -1237,7 +1254,8 @@
},
"extsprintf": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"forever-agent": {
"version": "0.6.1",
@@ -1256,11 +1274,13 @@
},
"fs.realpath": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"fstream": {
"version": "1.0.11",
"bundled": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
@@ -1311,6 +1331,7 @@
"glob": {
"version": "7.1.2",
"bundled": true,
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -1322,7 +1343,8 @@
},
"graceful-fs": {
"version": "4.1.11",
"bundled": true
"bundled": true,
"optional": true
},
"har-schema": {
"version": "1.0.5",
@@ -1346,6 +1368,7 @@
"hawk": {
"version": "3.1.3",
"bundled": true,
"optional": true,
"requires": {
"boom": "2.x.x",
"cryptiles": "2.x.x",
@@ -1355,7 +1378,8 @@
},
"hoek": {
"version": "2.16.3",
"bundled": true
"bundled": true,
"optional": true
},
"http-signature": {
"version": "1.1.1",
@@ -1370,6 +1394,7 @@
"inflight": {
"version": "1.0.6",
"bundled": true,
"optional": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@@ -1377,7 +1402,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.4",
@@ -1387,6 +1413,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -1398,7 +1425,8 @@
},
"isarray": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"isstream": {
"version": "0.1.2",
@@ -1461,11 +1489,13 @@
},
"mime-db": {
"version": "1.27.0",
"bundled": true
"bundled": true,
"optional": true
},
"mime-types": {
"version": "2.1.15",
"bundled": true,
"optional": true,
"requires": {
"mime-db": "~1.27.0"
}
@@ -1473,17 +1503,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -1533,7 +1566,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"oauth-sign": {
"version": "0.8.2",
@@ -1548,6 +1582,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -1573,7 +1608,8 @@
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"performance-now": {
"version": "0.2.0",
@@ -1582,7 +1618,8 @@
},
"process-nextick-args": {
"version": "1.0.7",
"bundled": true
"bundled": true,
"optional": true
},
"punycode": {
"version": "1.4.1",
@@ -1615,6 +1652,7 @@
"readable-stream": {
"version": "2.2.9",
"bundled": true,
"optional": true,
"requires": {
"buffer-shims": "~1.0.0",
"core-util-is": "~1.0.0",
@@ -1657,13 +1695,15 @@
"rimraf": {
"version": "2.6.1",
"bundled": true,
"optional": true,
"requires": {
"glob": "^7.0.5"
}
},
"safe-buffer": {
"version": "5.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"semver": {
"version": "5.3.0",
@@ -1683,6 +1723,7 @@
"sntp": {
"version": "1.0.9",
"bundled": true,
"optional": true,
"requires": {
"hoek": "2.x.x"
}
@@ -1713,6 +1754,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -1722,6 +1764,7 @@
"string_decoder": {
"version": "1.0.1",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.0.1"
}
@@ -1734,6 +1777,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -1746,6 +1790,7 @@
"tar": {
"version": "2.2.1",
"bundled": true,
"optional": true,
"requires": {
"block-stream": "*",
"fstream": "^1.0.2",
@@ -1795,7 +1840,8 @@
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
},
"uuid": {
"version": "3.0.1",
@@ -1820,7 +1866,8 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true
"bundled": true,
"optional": true
}
}
},
@@ -2760,7 +2807,8 @@
"hoek": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
"optional": true
},
"homedir-polyfill": {
"version": "1.0.1",
@@ -3522,12 +3570,14 @@
"mime-db": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz",
"integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg="
"integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=",
"optional": true
},
"mime-types": {
"version": "2.1.16",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz",
"integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=",
"optional": true,
"requires": {
"mime-db": "~1.29.0"
}

View File

@@ -1,4 +1,4 @@
using NzbDrone.Api.REST;
using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Config
@@ -11,6 +11,7 @@ namespace NzbDrone.Api.Config
public bool EnableCompletedDownloadHandling { get; set; }
public bool RemoveCompletedDownloads { get; set; }
public int CheckForFinishedDownloadInterval { get; set; }
public bool AutoRedownloadFailed { get; set; }
public bool RemoveFailedDownloads { get; set; }
@@ -28,6 +29,7 @@ namespace NzbDrone.Api.Config
EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling,
RemoveCompletedDownloads = model.RemoveCompletedDownloads,
CheckForFinishedDownloadInterval = model.CheckForFinishedDownloadInterval,
AutoRedownloadFailed = model.AutoRedownloadFailed,
RemoveFailedDownloads = model.RemoveFailedDownloads

View File

@@ -5,6 +5,7 @@ using System.Linq;
using Nancy;
using Nancy.Bootstrapper;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Api.Extensions.Pipelines
@@ -15,9 +16,14 @@ namespace NzbDrone.Api.Extensions.Pipelines
public int Order => 0;
private readonly Action<Action<Stream>, Stream> _writeGZipStream;
public GzipCompressionPipeline(Logger logger)
{
_logger = logger;
// On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case.
_writeGZipStream = OsInfo.IsMonoRuntime ? WriteGZipStreamMono : (Action<Action<Stream>, Stream>)WriteGZipStream;
}
public void Register(IPipelines pipelines)
@@ -43,14 +49,7 @@ namespace NzbDrone.Api.Extensions.Pipelines
var contents = response.Contents;
response.Headers["Content-Encoding"] = "gzip";
response.Contents = responseStream =>
{
using (var gzip = new GZipStream(responseStream, CompressionMode.Compress, true))
using (var buffered = new BufferedStream(gzip, 8192))
{
contents.Invoke(buffered);
}
};
response.Contents = responseStream => _writeGZipStream(contents, responseStream);
}
}
@@ -61,6 +60,25 @@ namespace NzbDrone.Api.Extensions.Pipelines
}
}
private static void WriteGZipStreamMono(Action<Stream> innerContent, Stream targetStream)
{
using (var membuffer = new MemoryStream())
{
WriteGZipStream(innerContent, membuffer);
membuffer.Position = 0;
membuffer.CopyTo(targetStream);
}
}
private static void WriteGZipStream(Action<Stream> innerContent, Stream targetStream)
{
using (var gzip = new GZipStream(targetStream, CompressionMode.Compress, true))
using (var buffered = new BufferedStream(gzip, 8192))
{
innerContent.Invoke(buffered);
}
}
private static bool ContentLengthIsTooSmall(Response response)
{
var contentLength = response.Headers.GetValueOrDefault("Content-Length");

View File

@@ -24,6 +24,7 @@ namespace NzbDrone.Api.NetImport
resource.RootFolderPath = definition.RootFolderPath;
resource.ShouldMonitor = definition.ShouldMonitor;
resource.MinimumAvailability = definition.MinimumAvailability;
resource.Tags = definition.Tags;
}
protected override void MapToModel(NetImportDefinition definition, NetImportResource resource)
@@ -36,6 +37,7 @@ namespace NzbDrone.Api.NetImport
definition.RootFolderPath = resource.RootFolderPath;
definition.ShouldMonitor = resource.ShouldMonitor;
definition.MinimumAvailability = resource.MinimumAvailability;
definition.Tags = resource.Tags;
}
protected override void Validate(NetImportDefinition definition, bool includeWarnings)

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using NzbDrone.Core.Movies;
namespace NzbDrone.Api.NetImport
@@ -10,5 +11,6 @@ namespace NzbDrone.Api.NetImport
public string RootFolderPath { get; set; }
public int ProfileId { get; set; }
public MovieStatusType MinimumAvailability { get; set; }
public HashSet<int> Tags { get; set; }
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
@@ -26,11 +28,20 @@ namespace NzbDrone.Common.Http.Dispatchers
{
webRequest = (HttpWebRequest) WebRequest.Create((Uri) request.Url);
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
if (OsInfo.IsMonoRuntime)
{
// On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case.
webRequest.AutomaticDecompression = DecompressionMethods.None;
webRequest.Headers.Add("Accept-Encoding", "gzip");
}
else
{
// Deflate is not a standard and could break depending on implementation.
// we should just stick with the more compatible Gzip
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
}
webRequest.Method = request.Method.ToString();
webRequest.UserAgent = request.UseSimplifiedUserAgent
? UserAgentBuilder.UserAgentSimplified
@@ -86,6 +97,19 @@ namespace NzbDrone.Common.Http.Dispatchers
if (responseStream != null)
{
data = responseStream.ToBytes();
if (OsInfo.IsMonoRuntime && httpWebResponse.ContentEncoding == "gzip")
{
using (var compressedStream = new MemoryStream(data))
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var decompressedStream = new MemoryStream())
{
gzip.CopyTo(decompressedStream);
data = decompressedStream.ToArray();
}
httpWebResponse.Headers.Remove("Content-Encoding");
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
@@ -135,7 +135,7 @@ namespace NzbDrone.Common.Http
return new HttpUri(Scheme, Host, Port, CombinePath(Path, path), Query, Fragment);
}
private static string CombinePath(string basePath, string relativePath)
public static string CombinePath(string basePath, string relativePath)
{
if (relativePath.IsNullOrWhiteSpace())
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Text.RegularExpressions;
using FluentAssertions;
using NUnit.Framework;
@@ -23,6 +23,8 @@ namespace NzbDrone.Core.Test.CustomFormat
[TestCase("S_WEBdL", TagType.Source, Source.WEBDL)]
[TestCase("S_CAM", TagType.Source, Source.CAM)]
[TestCase("L_English", TagType.Language, Language.English)]
[TestCase("L_Italian", TagType.Language, Language.Italian)]
[TestCase("L_iTa", TagType.Language, Language.Italian)]
[TestCase("L_germaN", TagType.Language, Language.German)]
[TestCase("E_Director", TagType.Edition, "director")]
[TestCase("E_RX_Director('?s)?", TagType.Edition, "director('?s)?", TagModifier.Regex)]

View File

@@ -19,6 +19,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
private NzbgetQueueItem _queued;
private NzbgetHistoryItem _failed;
private NzbgetHistoryItem _completed;
private Dictionary<string, string> _configItems;
[SetUp]
public void Setup()
@@ -80,13 +81,17 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
DownloadRate = 7000000
});
var configItems = new Dictionary<string, string>();
configItems.Add("Category1.Name", "movie");
configItems.Add("Category1.DestDir", @"/remote/mount/movie");
Mocker.GetMock<INzbgetProxy>()
.Setup(v => v.GetVersion(It.IsAny<NzbgetSettings>()))
.Returns("14.0");
_configItems = new Dictionary<string, string>();
_configItems.Add("Category1.Name", "movie");
_configItems.Add("Category1.DestDir", @"/remote/mount/movie");
Mocker.GetMock<INzbgetProxy>()
.Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>()))
.Returns(configItems);
.Returns(_configItems);
}
protected void GivenFailedDownload()
@@ -386,5 +391,18 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
error.IsValid.Should().Be(expected);
}
[TestCase("0", false)]
[TestCase("1", true)]
[TestCase(" 7", false)]
[TestCase("5000000", false)]
public void should_test_keephistory(string keephistory, bool expected)
{
_configItems["KeepHistory"] = keephistory;
var error = Subject.Test();
error.IsValid.Should().Be(expected);
}
}
}

View File

@@ -0,0 +1,43 @@
using System.IO;
using NUnit.Framework;
using NzbDrone.Core.Download;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Download
{
[TestFixture]
public class NzbValidationServiceFixture : CoreTest<NzbValidationService>
{
private byte[] GivenNzbFile(string name)
{
return File.ReadAllBytes(GetTestPath("Files/Nzbs/" + name + ".nzb"));
}
[Test]
public void should_throw_on_invalid_nzb()
{
var filename = "NotNzb";
var fileContent = GivenNzbFile(filename);
Assert.Throws<InvalidNzbException>(() => Subject.Validate(filename, fileContent));
}
[Test]
public void should_throw_when_no_files()
{
var filename = "NoFiles";
var fileContent = GivenNzbFile(filename);
Assert.Throws<InvalidNzbException>(() => Subject.Validate(filename, fileContent));
}
[Test]
public void should_validate_nzb()
{
var filename = "ValidNzb";
var fileContent = GivenNzbFile(filename);
Subject.Validate(filename, fileContent);
}
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE nzb
PUBLIC '-//newzBin//DTD NZB 1.1//EN'
'http://www.newzbin.com/DTD/nzb/nzb-1.1.dtd'>
<nzb xmlns="http://www.newzbin.com/DTD/2003/nzb">
</nzb>

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<fail>
<file date="1504571104" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[01/46] - &quot;Series.Title.s04e06.720p.hdtv.x264-killers.nfo&quot; yEnc (1/1)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="12053" number="1">ZQ9h749E781168561i4J0Q6-01m6Q3185@2894t-767038L.Pg7769</segment>
</segments>
</file>
<file date="1504571104" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[02/46] - &quot;Series.Title.s04e06.720p.hdtv.x264-killers.par2&quot; yEnc (1/1)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="26932" number="1">405Z5Y4066010l377VP1k6$U4873W933@f32Bs90575538201.pj54</segment>
</segments>
</file>
<file date="1504571104" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[03/46] - &quot;Series.Title.s04e06.720p.hdtv.x264-killers.r00&quot; yEnc (1/66)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="793068" number="1">1x9894417$M.1s25279485O1s1Fi95Z1_18Z554u440@D1k0854_134551.0794144</segment>
<segment bytes="793234" number="2">48JYp$W18B2R1s2rI24EG7$907$r89875n60@8xK3374080716.115545M</segment>
<segment bytes="793346" number="3">0U93471uI59Y781x77Q8-4286308-4aU35$07-179z@u90567568251.4zgUW968</segment>
<segment bytes="793302" number="4">5119x6417a.s06F$1k46$2q89298-C0@G7C-7811268.bK9x00B</segment>
<segment bytes="793289" number="5">B8$1_h0b64Z14-16_O6$ESw481L421n9agj7731k@414.473581-K$4.0Zd5A</segment>
<segment bytes="793380" number="6">O-4731$tn71v05623J9GT.yc22O975111dR01r58065p@Da1G9L33q74h3095.5X240</segment>
<segment bytes="793253" number="7">d9R03J$07w75945Z556197z50F0w.0-5.x9$58311S@J0-v50033110.4a440EYJ</segment>
<segment bytes="793317" number="8">05e650149.5r1Hk$E0Bko7G5B.1107mz8l17PS8F@vr816$S6T19245w.042B9</segment>
<segment bytes="793060" number="9">245Xy0w4o$tN6428321b.n1816Q1n95bE0816Y@q-qv7E12k.F3672H.16E19</segment>
<segment bytes="793266" number="10">H681i185g64H23101kP125z41101O91P384l@E9n597k05j798D94X.2ezz1K</segment>
<segment bytes="793223" number="11">T18.6136787.HLJ806.8$Si49m0459445101Z15-5@b80M7.788598D.gXu201cR</segment>
<segment bytes="793346" number="12">Vdl8H243Go28j1o865772039416v2@090a20-v365N5S7qf.G225s6</segment>
<segment bytes="793305" number="13">S9769892v956069345.0TN.i05R@I04825Gt2706N.BAj1DT1T</segment>
<segment bytes="793187" number="14">041800q6F28q44365799m5CQ4D43895@1Bf6268z_Q20F.045JXl</segment>
<segment bytes="793119" number="15">1c-e034z4l$9K45i44218ss25$X5_5R-1i76$40-71P@Xt691t8B686Fgv.VBSl</segment>
<segment bytes="793262" number="16">76l441W.R146a5368ed02cp_44171410hT.l@Z98.k.70X9c.5mZ1w49</segment>
<segment bytes="793221" number="17">12D035G5745-KO43wZ9920ttr1338@V7d871S2-t04t8520.uQ18</segment>
<segment bytes="793221" number="18">59V4O77211HA1f5T8h1-53952zV-55294K4M04v@kS878H3g4z.B5561.L330519</segment>
<segment bytes="793087" number="19">44-yi1-79$751944J7094$y7-y49994440d86cSn@5C82v-1O9N.wk8wMb6</segment>
<segment bytes="793375" number="20">oF7Wj3$Ydh7e030oD4.e81JM464O791495lJ@Pm058Qt4-G8Wv.T1i1a6O1</segment>
<segment bytes="793293" number="21">1T7_71M9d10F2.5953VP.11.4h75L@5049bBn384.14Ms</segment>
<segment bytes="793266" number="22">u8601765028G662749SD41j0m57651Zq70u1@J5281423406375.z.6PDSx57</segment>
<segment bytes="793376" number="23">XY0476$R87Y16g2n45OO335541589V140R026j@y2q9296x7f23C.sqK71b9</segment>
<segment bytes="793363" number="24">X7N3440l08B9T5940na4Ls397-T2.P5M12241525J57@r44O419p594M6G4I.d66RQ1</segment>
<segment bytes="793203" number="25">p4148978k45.t88w2K9886H4223y5553T7$7p287TN@N8e1T98b_0.mo55a14G</segment>
<segment bytes="793039" number="26">50U0a9iP07$A66010-51h55w386f@c$42$S96V57F5u0Y.6UDV35D</segment>
<segment bytes="792999" number="27">FnKN4n2749v958xa36J2570506414D293S@8H1A1X490$z3bv.ut6KQ4N</segment>
<segment bytes="793316" number="28">q4$d0$X8x6rm85m0Ewh307m255N@t2C7484zq870u.1RLndQ</segment>
<segment bytes="793238" number="29">364U4342$5I242404oH90-1W3c0t16705057m650Cq9f@K32rE5297347130W.UNs8evbH</segment>
<segment bytes="793461" number="30">M3081U097-r06Y.yy9-1A538001B27f@L2834Y80c7b1075.Dy150</segment>
<segment bytes="793326" number="31">189585554.NS66E5D840N4Yq5m07NC1n@51L0393057L528n.k1Mc3j0S</segment>
<segment bytes="793380" number="32">189048V505q89216C149I5f$53x-T@0V9i8n7o95.I.Z1lBJ5</segment>
<segment bytes="793205" number="33">5-L.555$139r45100-S23-59859@54844694q2.3EY9b</segment>
<segment bytes="793258" number="34">641655313y0.Z002L0g39AZ11716U-uX015PI5.v6y@veS44H89Js91903K8.P3MAvk4k</segment>
<segment bytes="793229" number="35">1C8f-yz-U-b20.610.0P1M-6Z5418i229160865010s1@M7l210D48Nc.nB0sPmi</segment>
<segment bytes="793169" number="36">0653$L0.58749-1U_1PS95-1h9gQ145@0117y0-1x1p-h94.za18yc5</segment>
<segment bytes="793109" number="37">77-Mo3-a6514904987865.K0W710G4HB9237@501F7910J6j50-Bh.6cHx1</segment>
<segment bytes="793350" number="38">m4I47082655rz$b7P751u9W679475F.89p@f.o.XZv5O7y.855rgXX</segment>
<segment bytes="793193" number="39">f075$y56E57d.t11787.0$6D155735M_w89-Y57q2@x0t5H91021wZ52Vh.1h7vabU</segment>
<segment bytes="793251" number="40">H7U1331Ad7718$Y69T-q3w4$l247HV49s985J@vi800i0004p.YD5oK</segment>
<segment bytes="793106" number="41">9nr786955Ker.M583315CoJ1-W65a817-704@IN-wU12$M1E0g466.5sMJ3</segment>
<segment bytes="793006" number="42">0.3R9mN.n2_V086N0-4.Z5gAgZo@ey3G316U382o537.f51Ed5B</segment>
<segment bytes="793198" number="43">l106Z1-N411r7j44197l628r.b5Uwc55@k4-Cl_n5xc.1B.xZbNm</segment>
<segment bytes="793070" number="44">A91LT1X591x81.TI4130N$555A57q0@L70-p5qa50.40GB</segment>
<segment bytes="793457" number="45">V5$765JR6503w0-K63099R615736843G$Qj0ev@mz776wM86445N0.4I56ne</segment>
<segment bytes="793109" number="46">A86H2P415S689$568152-025O45V@s079644915.Dd57p0</segment>
<segment bytes="793169" number="47">31x5o36q14y9554L42882X0Q10e360Z64W4K9Onx38D@5g1509788414q.Y8wib</segment>
<segment bytes="793219" number="48">b$6795157EX1044V964e14-Y9E68614O94C@4061937876$f5.6.19tV</segment>
<segment bytes="793349" number="49">D00v8X$b80m93181273J-g076Qj2p79867v5d9689Rb2@r0592.v900.j43E050E</segment>
<segment bytes="793228" number="50">Tf78L4e535.o86PK0S.M2R3-66012814z@q-5j89Y29J214Y902.53Ra0f</segment>
<segment bytes="793353" number="51">7i01.23411-lQW0212-Er260e9.N5e256jx243EX@91-T.15v40K5Hj.Fo1f</segment>
<segment bytes="793290" number="52">3A$H7m63$i595.4713vv0A4$A7Lk7Jsq@0cM0Tw4107f.B520.q5Z91</segment>
<segment bytes="793364" number="53">j572m$3h87LS$37167Wp10k41541.T779-Fn@V53C11045619xJ.52.0PnnX4v5</segment>
<segment bytes="793506" number="54">A.2d4599a720rk2IB32h0X523MjTL415v89706-7Z45y@R4746-B106358.t3g62r4</segment>
<segment bytes="793118" number="55">5q6100961jM-G9F7t755x366zxc102M1SdMF@7394521p651X1I.AL05545a</segment>
<segment bytes="793137" number="56">04e851111$12u2213-80VR133125B@7x8865M4hQ9$5.1N345x</segment>
<segment bytes="793180" number="57">K2476D3600-73B4W363$008s888980421f27125V$q0@0Zc0a56-m7550.1637vAr1</segment>
<segment bytes="793214" number="58">0306u425024v448ZeCE3Q9825m9th1858@5648018-H0.2k7J4.12k0B</segment>
<segment bytes="793274" number="59">220u4SK433564Cr2l004t0wP888545779g@19j360863S$55559m.70V7Ndr</segment>
<segment bytes="793339" number="60">5u1q051C5Qq8Z9Iy$Z.5.1510NY.S2565n@7m.5-09$z235p74.8kW5</segment>
<segment bytes="793297" number="61">6F472C8nh2621_X0C1093P7n39643b5p2f76s60r@1T55203qQY6.wZml1Vb</segment>
<segment bytes="793351" number="62">5qC4568844767324-o8i05983-0f.n4.y.OBZ41f@q36B50684KU66.0R1784</segment>
<segment bytes="793257" number="63">4P0g470-F59307aDf.JF070Xx959648dO3y00463J6s@71P$D961$C0.11.I096sQ</segment>
<segment bytes="793277" number="64">z5kod75077z01w11-A5h.wiG550.J5-p756$81.Db@5l01K49h3K.Ok4R5512</segment>
<segment bytes="793292" number="65">F3JX28.B8h90T0075-08001X5w611V071@D75X9263$6$9f.OT050p5Z</segment>
<segment bytes="83545" number="66">2B8sT.A650z101514671183y47977219.M4211xYp@0b0021p736BX92.B0lSm4J3</segment>
</segments>
</file>
<file date="1504571157" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[46/46] - &quot;sample-Series.Title.s04e06.720p.hdtv.x264-killers.vol31+04.par2&quot; yEnc (1/3)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="793316" number="1">16ND-8I545Pq-s107t0h07g8908870711@K401476783.5.0mFs1</segment>
<segment bytes="793409" number="2">iYdZ2D11089F310711.ci-O7O4KG03@260c03388O84Kd.GCEgv</segment>
<segment bytes="6784" number="3">r63cDD59Mg1c95738Sn75085O4X7823V1@16V6-b87O21S1937O.lw17o1VS</segment>
</segments>
</file>
</fail>

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE nzb
PUBLIC '-//newzBin//DTD NZB 1.1//EN'
'http://www.newzbin.com/DTD/nzb/nzb-1.1.dtd'>
<nzb xmlns="http://www.newzbin.com/DTD/2003/nzb">
<file date="1504571104" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[01/46] - &quot;Series.Title.s04e06.720p.hdtv.x264-killers.nfo&quot; yEnc (1/1)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="12053" number="1">ZQ9h749E781168561i4J0Q6-01m6Q3185@2894t-767038L.Pg7769</segment>
</segments>
</file>
<file date="1504571104" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[02/46] - &quot;Series.Title.s04e06.720p.hdtv.x264-killers.par2&quot; yEnc (1/1)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="26932" number="1">405Z5Y4066010l377VP1k6$U4873W933@f32Bs90575538201.pj54</segment>
</segments>
</file>
<file date="1504571104" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[03/46] - &quot;Series.Title.s04e06.720p.hdtv.x264-killers.r00&quot; yEnc (1/66)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="793068" number="1">1x9894417$M.1s25279485O1s1Fi95Z1_18Z554u440@D1k0854_134551.0794144</segment>
<segment bytes="793234" number="2">48JYp$W18B2R1s2rI24EG7$907$r89875n60@8xK3374080716.115545M</segment>
<segment bytes="793346" number="3">0U93471uI59Y781x77Q8-4286308-4aU35$07-179z@u90567568251.4zgUW968</segment>
<segment bytes="793302" number="4">5119x6417a.s06F$1k46$2q89298-C0@G7C-7811268.bK9x00B</segment>
<segment bytes="793289" number="5">B8$1_h0b64Z14-16_O6$ESw481L421n9agj7731k@414.473581-K$4.0Zd5A</segment>
<segment bytes="793380" number="6">O-4731$tn71v05623J9GT.yc22O975111dR01r58065p@Da1G9L33q74h3095.5X240</segment>
<segment bytes="793253" number="7">d9R03J$07w75945Z556197z50F0w.0-5.x9$58311S@J0-v50033110.4a440EYJ</segment>
<segment bytes="793317" number="8">05e650149.5r1Hk$E0Bko7G5B.1107mz8l17PS8F@vr816$S6T19245w.042B9</segment>
<segment bytes="793060" number="9">245Xy0w4o$tN6428321b.n1816Q1n95bE0816Y@q-qv7E12k.F3672H.16E19</segment>
<segment bytes="793266" number="10">H681i185g64H23101kP125z41101O91P384l@E9n597k05j798D94X.2ezz1K</segment>
<segment bytes="793223" number="11">T18.6136787.HLJ806.8$Si49m0459445101Z15-5@b80M7.788598D.gXu201cR</segment>
<segment bytes="793346" number="12">Vdl8H243Go28j1o865772039416v2@090a20-v365N5S7qf.G225s6</segment>
<segment bytes="793305" number="13">S9769892v956069345.0TN.i05R@I04825Gt2706N.BAj1DT1T</segment>
<segment bytes="793187" number="14">041800q6F28q44365799m5CQ4D43895@1Bf6268z_Q20F.045JXl</segment>
<segment bytes="793119" number="15">1c-e034z4l$9K45i44218ss25$X5_5R-1i76$40-71P@Xt691t8B686Fgv.VBSl</segment>
<segment bytes="793262" number="16">76l441W.R146a5368ed02cp_44171410hT.l@Z98.k.70X9c.5mZ1w49</segment>
<segment bytes="793221" number="17">12D035G5745-KO43wZ9920ttr1338@V7d871S2-t04t8520.uQ18</segment>
<segment bytes="793221" number="18">59V4O77211HA1f5T8h1-53952zV-55294K4M04v@kS878H3g4z.B5561.L330519</segment>
<segment bytes="793087" number="19">44-yi1-79$751944J7094$y7-y49994440d86cSn@5C82v-1O9N.wk8wMb6</segment>
<segment bytes="793375" number="20">oF7Wj3$Ydh7e030oD4.e81JM464O791495lJ@Pm058Qt4-G8Wv.T1i1a6O1</segment>
<segment bytes="793293" number="21">1T7_71M9d10F2.5953VP.11.4h75L@5049bBn384.14Ms</segment>
<segment bytes="793266" number="22">u8601765028G662749SD41j0m57651Zq70u1@J5281423406375.z.6PDSx57</segment>
<segment bytes="793376" number="23">XY0476$R87Y16g2n45OO335541589V140R026j@y2q9296x7f23C.sqK71b9</segment>
<segment bytes="793363" number="24">X7N3440l08B9T5940na4Ls397-T2.P5M12241525J57@r44O419p594M6G4I.d66RQ1</segment>
<segment bytes="793203" number="25">p4148978k45.t88w2K9886H4223y5553T7$7p287TN@N8e1T98b_0.mo55a14G</segment>
<segment bytes="793039" number="26">50U0a9iP07$A66010-51h55w386f@c$42$S96V57F5u0Y.6UDV35D</segment>
<segment bytes="792999" number="27">FnKN4n2749v958xa36J2570506414D293S@8H1A1X490$z3bv.ut6KQ4N</segment>
<segment bytes="793316" number="28">q4$d0$X8x6rm85m0Ewh307m255N@t2C7484zq870u.1RLndQ</segment>
<segment bytes="793238" number="29">364U4342$5I242404oH90-1W3c0t16705057m650Cq9f@K32rE5297347130W.UNs8evbH</segment>
<segment bytes="793461" number="30">M3081U097-r06Y.yy9-1A538001B27f@L2834Y80c7b1075.Dy150</segment>
<segment bytes="793326" number="31">189585554.NS66E5D840N4Yq5m07NC1n@51L0393057L528n.k1Mc3j0S</segment>
<segment bytes="793380" number="32">189048V505q89216C149I5f$53x-T@0V9i8n7o95.I.Z1lBJ5</segment>
<segment bytes="793205" number="33">5-L.555$139r45100-S23-59859@54844694q2.3EY9b</segment>
<segment bytes="793258" number="34">641655313y0.Z002L0g39AZ11716U-uX015PI5.v6y@veS44H89Js91903K8.P3MAvk4k</segment>
<segment bytes="793229" number="35">1C8f-yz-U-b20.610.0P1M-6Z5418i229160865010s1@M7l210D48Nc.nB0sPmi</segment>
<segment bytes="793169" number="36">0653$L0.58749-1U_1PS95-1h9gQ145@0117y0-1x1p-h94.za18yc5</segment>
<segment bytes="793109" number="37">77-Mo3-a6514904987865.K0W710G4HB9237@501F7910J6j50-Bh.6cHx1</segment>
<segment bytes="793350" number="38">m4I47082655rz$b7P751u9W679475F.89p@f.o.XZv5O7y.855rgXX</segment>
<segment bytes="793193" number="39">f075$y56E57d.t11787.0$6D155735M_w89-Y57q2@x0t5H91021wZ52Vh.1h7vabU</segment>
<segment bytes="793251" number="40">H7U1331Ad7718$Y69T-q3w4$l247HV49s985J@vi800i0004p.YD5oK</segment>
<segment bytes="793106" number="41">9nr786955Ker.M583315CoJ1-W65a817-704@IN-wU12$M1E0g466.5sMJ3</segment>
<segment bytes="793006" number="42">0.3R9mN.n2_V086N0-4.Z5gAgZo@ey3G316U382o537.f51Ed5B</segment>
<segment bytes="793198" number="43">l106Z1-N411r7j44197l628r.b5Uwc55@k4-Cl_n5xc.1B.xZbNm</segment>
<segment bytes="793070" number="44">A91LT1X591x81.TI4130N$555A57q0@L70-p5qa50.40GB</segment>
<segment bytes="793457" number="45">V5$765JR6503w0-K63099R615736843G$Qj0ev@mz776wM86445N0.4I56ne</segment>
<segment bytes="793109" number="46">A86H2P415S689$568152-025O45V@s079644915.Dd57p0</segment>
<segment bytes="793169" number="47">31x5o36q14y9554L42882X0Q10e360Z64W4K9Onx38D@5g1509788414q.Y8wib</segment>
<segment bytes="793219" number="48">b$6795157EX1044V964e14-Y9E68614O94C@4061937876$f5.6.19tV</segment>
<segment bytes="793349" number="49">D00v8X$b80m93181273J-g076Qj2p79867v5d9689Rb2@r0592.v900.j43E050E</segment>
<segment bytes="793228" number="50">Tf78L4e535.o86PK0S.M2R3-66012814z@q-5j89Y29J214Y902.53Ra0f</segment>
<segment bytes="793353" number="51">7i01.23411-lQW0212-Er260e9.N5e256jx243EX@91-T.15v40K5Hj.Fo1f</segment>
<segment bytes="793290" number="52">3A$H7m63$i595.4713vv0A4$A7Lk7Jsq@0cM0Tw4107f.B520.q5Z91</segment>
<segment bytes="793364" number="53">j572m$3h87LS$37167Wp10k41541.T779-Fn@V53C11045619xJ.52.0PnnX4v5</segment>
<segment bytes="793506" number="54">A.2d4599a720rk2IB32h0X523MjTL415v89706-7Z45y@R4746-B106358.t3g62r4</segment>
<segment bytes="793118" number="55">5q6100961jM-G9F7t755x366zxc102M1SdMF@7394521p651X1I.AL05545a</segment>
<segment bytes="793137" number="56">04e851111$12u2213-80VR133125B@7x8865M4hQ9$5.1N345x</segment>
<segment bytes="793180" number="57">K2476D3600-73B4W363$008s888980421f27125V$q0@0Zc0a56-m7550.1637vAr1</segment>
<segment bytes="793214" number="58">0306u425024v448ZeCE3Q9825m9th1858@5648018-H0.2k7J4.12k0B</segment>
<segment bytes="793274" number="59">220u4SK433564Cr2l004t0wP888545779g@19j360863S$55559m.70V7Ndr</segment>
<segment bytes="793339" number="60">5u1q051C5Qq8Z9Iy$Z.5.1510NY.S2565n@7m.5-09$z235p74.8kW5</segment>
<segment bytes="793297" number="61">6F472C8nh2621_X0C1093P7n39643b5p2f76s60r@1T55203qQY6.wZml1Vb</segment>
<segment bytes="793351" number="62">5qC4568844767324-o8i05983-0f.n4.y.OBZ41f@q36B50684KU66.0R1784</segment>
<segment bytes="793257" number="63">4P0g470-F59307aDf.JF070Xx959648dO3y00463J6s@71P$D961$C0.11.I096sQ</segment>
<segment bytes="793277" number="64">z5kod75077z01w11-A5h.wiG550.J5-p756$81.Db@5l01K49h3K.Ok4R5512</segment>
<segment bytes="793292" number="65">F3JX28.B8h90T0075-08001X5w611V071@D75X9263$6$9f.OT050p5Z</segment>
<segment bytes="83545" number="66">2B8sT.A650z101514671183y47977219.M4211xYp@0b0021p736BX92.B0lSm4J3</segment>
</segments>
</file>
<file date="1504571157" poster="autom@gical.tv (M@GiC)" subject="[432278]-[FULL]-[#a.b.teevee@EFNet]-[ Series.Title.S04E06.720p.HDTV.x264-KILLERS ]-[46/46] - &quot;sample-Series.Title.s04e06.720p.hdtv.x264-killers.vol31+04.par2&quot; yEnc (1/3)">
<groups>
<group>alt.binaries.teevee</group>
</groups>
<segments>
<segment bytes="793316" number="1">16ND-8I545Pq-s107t0h07g8908870711@K401476783.5.0mFs1</segment>
<segment bytes="793409" number="2">iYdZ2D11089F310711.ci-O7O4KG03@260c03388O84Kd.GCEgv</segment>
<segment bytes="6784" number="3">r63cDD59Mg1c95738Sn75085O4X7823V1@16V6-b87O21S1937O.lw17o1VS</segment>
</segments>
</file>
</nzb>

View File

@@ -1,4 +1,4 @@
using Moq;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
@@ -24,6 +24,64 @@ namespace NzbDrone.Core.Test.IndexerTests.IPTorrentsTests
};
}
private void GivenOldFeedFormat()
{
Subject.Definition = new IndexerDefinition()
{
Name = "IPTorrents",
Settings = new IPTorrentsSettings() { BaseUrl = "https://iptorrents.com/torrents/rss?u=snip;tp=snip;3;80;93;37;download" }
};
}
private void GivenNewFeedFormat()
{
Subject.Definition = new IndexerDefinition()
{
Name = "IPTorrents",
Settings = new IPTorrentsSettings() { BaseUrl = "https://iptorrents.com/t.rss?u=USERID;tp=APIKEY;3;80;93;37;download" }
};
}
private void GivenFeedNoDownloadFormat()
{
Subject.Definition = new IndexerDefinition()
{
Name = "IPTorrents",
Settings = new IPTorrentsSettings() { BaseUrl = "https://iptorrents.com/t.rss?u=USERID;tp=APIKEY;3;80;93;37" }
};
}
[Test]
public void should_validate_old_feed_format()
{
GivenOldFeedFormat();
var validationResult = Subject.Definition.Settings.Validate();
validationResult.IsValid.Should().BeTrue();
}
[Test]
public void should_validate_new_feed_format()
{
GivenNewFeedFormat();
var validationResult = Subject.Definition.Settings.Validate();
validationResult.IsValid.Should().BeTrue();
}
[Test]
public void should_not_validate_bad_format()
{
var validationResult = Subject.Definition.Settings.Validate();
validationResult.IsValid.Should().BeFalse();
}
[Test]
public void should_not_validate_no_download_format()
{
GivenFeedNoDownloadFormat();
var validationResult = Subject.Definition.Settings.Validate();
validationResult.IsValid.Should().BeFalse();
}
[Test]
public void should_parse_recent_feed_from_IPTorrents()
{

View File

@@ -195,6 +195,7 @@
<Compile Include="Download\DownloadClientTests\DownloadStationTests\UsenetDownloadStationFixture.cs" />
<Compile Include="Download\DownloadServiceFixture.cs" />
<Compile Include="Download\FailedDownloadServiceFixture.cs" />
<Compile Include="Download\NzbValidationServiceFixture.cs" />
<Compile Include="Download\Pending\PendingReleaseServiceTests\PendingReleaseServiceFixture.cs" />
<Compile Include="Download\Pending\PendingReleaseServiceTests\RemovePendingFixture.cs" />
<Compile Include="Download\Pending\PendingReleaseServiceTests\RemoveRejectedFixture.cs" />
@@ -553,6 +554,15 @@
</Content>
</ItemGroup>
<ItemGroup>
<None Include="Files\Nzbs\NoFiles.nzb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\Nzbs\NotNzb.nzb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\Nzbs\ValidNzb.nzb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Files\TestArchive.tar.gz">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@@ -584,4 +594,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@@ -49,6 +49,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("The Danish Girl 2015", Language.English)]
[TestCase("Nocturnal Animals (2016) MULTi VFQ English [1080p] BluRay x264-PopHD", Language.English, Language.French)]
[TestCase("Wonder.Woman.2017.720p.BluRay.DD5.1.x264-TayTO.CZ-FTU", Language.Czech)]
[TestCase("Fantastic.Beasts.The.Crimes.Of.Grindelwald.2018.2160p.WEBRip.x265.10bit.HDR.DD5.1-GASMASK", Language.English)]
public void should_parse_language(string postTitle, params Language[] languages)
{
var movieInfo = Parser.Parser.ParseMovieTitle(postTitle, true);
@@ -65,6 +66,8 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("2 Broke Girls - S01E01 - Pilot.en.sub", Language.English)]
[TestCase("2 Broke Girls - S01E01 - Pilot.eng.sub", Language.English)]
[TestCase("2 Broke Girls - S01E01 - Pilot.sub", Language.Unknown)]
[TestCase("2 Broke Girls - S01E01 - Pilot.eng.forced.sub", Language.English)]
[TestCase("2 Broke Girls - S01E01 - Pilot-eng-forced.sub", Language.English)]
public void should_parse_subtitle_language(string fileName, Language language)
{
var result = LanguageParser.ParseSubtitleLanguage(fileName);

View File

@@ -25,6 +25,8 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("test/test", "testtest")]
[TestCase("90210", "90210")]
[TestCase("24", "24")]
[TestCase("I'm a cyborg, but that's OK", "imcyborgbutthatsok")]
[TestCase("Im a cyborg, but thats ok", "imcyborgbutthatsok")]
public void should_remove_special_characters_and_casing(string dirty, string clean)
{
var result = dirty.CleanSeriesTitle();

View File

@@ -54,7 +54,9 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Scary.Movie.2000.FRENCH..BluRay.-AiRLiNE", "Scary Movie")]
[TestCase("My Movie 1999 German Bluray", "My Movie")]
[TestCase("Leaving Jeruselem by Railway (1897) [DVD].mp4", "Leaving Jeruselem by Railway")]
public void should_parse_movie_title(string postTitle, string title)
[TestCase("Climax.2018.1080p.AMZN.WEB-DL.DD5.1.H.264-NTG", "Climax")]
[TestCase("Movie.Title.Imax.2018.1080p.AMZN.WEB-DL.DD5.1.H.264-NTG", "Movie Title")]
public void should_parse_movie_title(string postTitle, string title)
{
Parser.Parser.ParseMovieTitle(postTitle, true).MovieTitle.Should().Be(title);
}
@@ -111,6 +113,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("My.Movie.GERMAN.Extended.Cut.2016", "Extended Cut")]
[TestCase("My.Movie.GERMAN.Extended.Cut", "Extended Cut")]
[TestCase("Mission Impossible: Rogue Nation 2012 Bluray", "")]
[TestCase("Loving.Pablo.2018.TS.FRENCH.MD.x264-DROGUERiE","")]
public void should_parse_edition(string postTitle, string edition)
{
var parsed = Parser.Parser.ParseMovieTitle(postTitle, true);

View File

@@ -207,6 +207,9 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("[Elysium]Lucky.Star.01(BD.720p.AAC.DA)[0BB96AD8].mkv", false)]
[TestCase("Battlestar.Galactica.S01E01.33.720p.HDDVD.x264-SiNNERS.mkv", false)]
[TestCase("The.Expanse.S01E07.RERIP.720p.BluRay.x264-DEMAND", true)]
[TestCase("John.Carpenter.Live.Retrospective.2016.2018.720p.MBluRay.x264-CRUELTY.mkv", false)]
[TestCase("Heart.Live.In.Atlantic.City.2019.720p.MBLURAY.x264-MBLURAYFANS.mkv", false)]
[TestCase("Opeth.Garden.Of.The.Titans.Live.At.Red.Rocks.Amphitheatre.2017.720p.MBluRay.x264-TREBLE.mkv", false)]
public void should_parse_bluray720p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R720P);
@@ -221,6 +224,9 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("[Zurako] Log Horizon - 01 - The Apocalypse (BD 1080p AAC) [7AE12174].mkv", false)]
[TestCase("WEEDS.S03E01-06.DUAL.1080p.Blu-ray.AC3.-HELLYWOOD.avi", false)]
[TestCase("[Coalgirls]_Durarara!!_01_(1920x1080_Blu-ray_FLAC)_[8370CB8F].mkv", false)]
[TestCase("John.Carpenter.Live.Retrospective.2016.2018.1080p.MBluRay.x264-CRUELTY.mkv", false)]
[TestCase("Heart.Live.In.Atlantic.City.2019.1080p.MBLURAY.x264-MBLURAYFANS.mkv", false)]
[TestCase("Opeth.Garden.Of.The.Titans.Live.At.Red.Rocks.Amphitheatre.2017.1080p.MBluRay.x264-TREBLE.mkv", false)]
public void should_parse_bluray1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R1080P);

View File

@@ -273,6 +273,13 @@ namespace NzbDrone.Core.Configuration
set { SetValue("DownloadedMoviesScanInterval", value); }
}
public int CheckForFinishedDownloadInterval
{
get { return GetValueInt("CheckForFinishedDownloadInterval", 1); }
set { SetValue("CheckForFinishedDownloadInterval", value); }
}
public int DownloadClientHistoryLimit
{
get { return GetValueInt("DownloadClientHistoryLimit", 30); }

View File

@@ -16,6 +16,7 @@ namespace NzbDrone.Core.Configuration
string DownloadClientWorkingFolders { get; set; }
int DownloadedMoviesScanInterval { get; set; }
int DownloadClientHistoryLimit { get; set; }
int CheckForFinishedDownloadInterval { get; set; }
//Completed/Failed Download Handling (Download client)
bool EnableCompletedDownloadHandling { get; set; }

View File

@@ -191,8 +191,8 @@ namespace NzbDrone.Core.CustomFormats
{
"Easy", new List<CustomFormat>
{
new CustomFormat("x264", "C_RX_(x|h)264"),
new CustomFormat("x265", "C_RX_(((x|h)265)|(HEVC))"),
new CustomFormat("x264", @"C_RX_(x|h)\.?264"),
new CustomFormat("x265", @"C_RX_(((x|h)\.?265)|(HEVC))"),
new CustomFormat("Simple Hardcoded Subs", "C_RX_subs?"),
new CustomFormat("Multi Language", "L_English", "L_French")
}

View File

@@ -83,7 +83,9 @@ namespace NzbDrone.Core.CustomFormats
var tuple = Value as (long, long)? ?? (0, 0);
return size > tuple.Item1 && size < tuple.Item2;
case TagType.Indexer:
#if !LIBRARY
return (movieInfo.ExtraInfo.GetValueOrDefault("IndexerFlags") as IndexerFlags?)?.HasFlag((IndexerFlags) Value) == true;
#endif
default:
return false;
}
@@ -188,6 +190,7 @@ namespace NzbDrone.Core.CustomFormats
Value = Parser.LanguageParser.ParseLanguages(value).First();
break;
case "i":
#if !LIBRARY
TagType = TagType.Indexer;
var flagValues = Enum.GetValues(typeof(IndexerFlags));
@@ -198,7 +201,7 @@ namespace NzbDrone.Core.CustomFormats
Value = flagValue;
break;
}
#endif
break;
case "g":
TagType = TagType.Size;

View File

@@ -0,0 +1,17 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(151)]
public class add_tags_to_net_import : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("NetImport")
.AddColumn("Tags").AsString().Nullable();
Execute.Sql("UPDATE NetImport SET Tags = '[]'");
}
}
}

View File

@@ -25,8 +25,9 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService,
Logger logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, nzbValidationService, logger)
{
_scanWatchFolder = scanWatchFolder;

View File

@@ -34,9 +34,10 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService,
Logger logger
)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, nzbValidationService, logger)
{
_dsInfoProxy = dsInfoProxy;
_dsTaskProxy = dsTaskProxy;

View File

@@ -25,8 +25,9 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService,
Logger logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, nzbValidationService, logger)
{
_proxy = proxy;
}

View File

@@ -12,6 +12,7 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
using NzbDrone.Core.RemotePathMappings;
using NzbDrone.Core.Organizer;
using System.Globalization;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
@@ -27,8 +28,9 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService,
Logger logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, nzbValidationService, logger)
{
_proxy = proxy;
}
@@ -53,19 +55,8 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
private IEnumerable<DownloadClientItem> GetQueue()
{
NzbgetGlobalStatus globalStatus;
List<NzbgetQueueItem> queue;
try
{
globalStatus = _proxy.GetGlobalStatus(Settings);
queue = _proxy.GetQueue(Settings);
}
catch (DownloadClientException ex)
{
_logger.Error(ex, ex.Message);
return Enumerable.Empty<DownloadClientItem>();
}
var globalStatus = _proxy.GetGlobalStatus(Settings);
var queue = _proxy.GetQueue(Settings);
var queueItems = new List<DownloadClientItem>();
@@ -121,17 +112,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
private IEnumerable<DownloadClientItem> GetHistory()
{
List<NzbgetHistoryItem> history;
try
{
history = _proxy.GetHistory(Settings).Take(_configService.DownloadClientHistoryLimit).ToList();
}
catch (DownloadClientException ex)
{
_logger.Error(ex, ex.Message);
return Enumerable.Empty<DownloadClientItem>();
}
var history = _proxy.GetHistory(Settings).Take(_configService.DownloadClientHistoryLimit).ToList();
var historyItems = new List<DownloadClientItem>();
@@ -307,7 +288,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
return new NzbDroneValidationFailure("MovieCategory", "Category does not exist")
{
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings),
DetailedDescription = "The category you entered doesn't exist in NZBGet. Go to NZBGet to create it."
};
}
@@ -319,13 +300,22 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
var config = _proxy.GetConfig(Settings);
var keepHistory = config.GetValueOrDefault("KeepHistory");
if (keepHistory == "0")
var keepHistory = config.GetValueOrDefault("KeepHistory", "7");
int value;
if (!int.TryParse(keepHistory, NumberStyles.None, CultureInfo.InvariantCulture, out value) || value == 0)
{
return new NzbDroneValidationFailure(string.Empty, "NZBGet setting KeepHistory should be greater than 0")
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 0")
{
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
DetailedDescription = "NZBGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
InfoLink = _proxy.GetBaseUrl(Settings),
DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
};
}
else if (value > 25000)
{
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be less than 25000")
{
InfoLink = _proxy.GetBaseUrl(Settings),
DetailedDescription = "NzbGet setting KeepHistory is set too high."
};
}

View File

@@ -11,6 +11,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
public interface INzbgetProxy
{
string GetBaseUrl(NzbgetSettings settings, string relativePath = null);
string DownloadNzb(byte[] nzbData, string title, string category, int priority, bool addpaused, NzbgetSettings settings);
NzbgetGlobalStatus GetGlobalStatus(NzbgetSettings settings);
List<NzbgetQueueItem> GetQueue(NzbgetSettings settings);
@@ -36,9 +37,17 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
_versionCache = cacheManager.GetCache<string>(GetType(), "versions");
}
public string GetBaseUrl(NzbgetSettings settings, string relativePath = null)
{
var baseUrl = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase);
baseUrl = HttpUri.CombinePath(baseUrl, relativePath);
return baseUrl;
}
private bool HasVersion(int minimumVersion, NzbgetSettings settings)
{
var versionString = _versionCache.Find(settings.Host + ":" + settings.Port) ?? GetVersion(settings);
var versionString = _versionCache.Find(GetBaseUrl(settings)) ?? GetVersion(settings);
var version = int.Parse(versionString.Split(new[] { '.', '-' })[0]);
@@ -139,7 +148,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
var response = ProcessRequest<string>(settings, "version");
_versionCache.Set(settings.Host + ":" + settings.Port, response, TimeSpan.FromDays(1));
_versionCache.Set(GetBaseUrl(settings), response, TimeSpan.FromDays(1));
return response;
}
@@ -170,7 +179,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
queueItem = queue.SingleOrDefault(h => h.Parameters.Any(p => p.Name == "drone" && id == (p.Value as string)));
historyItem = history.SingleOrDefault(h => h.Parameters.Any(p => p.Name == "drone" && id == (p.Value as string)));
}
if (queueItem != null)
{
if (!EditQueue("GroupFinalDelete", 0, "", queueItem.NzbId, settings))
@@ -218,7 +227,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
private T ProcessRequest<T>(NzbgetSettings settings, string method, params object[] parameters)
{
var baseUrl = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, "jsonrpc");
var baseUrl = GetBaseUrl(settings, "jsonrpc");
var requestBuilder = new JsonRpcRequestBuilder(baseUrl, method, parameters);
requestBuilder.LogResponseContent = true;

View File

@@ -1,4 +1,5 @@
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -11,6 +12,8 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.Port).InclusiveBetween(1, 65535);
RuleFor(c => c.UrlBase).ValidUrlBase().When(c => c.UrlBase.IsNotNullOrWhiteSpace());
RuleFor(c => c.Username).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Password));
RuleFor(c => c.Password).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Username));
@@ -39,25 +42,28 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)]
public int Port { get; set; }
[FieldDefinition(2, Label = "Username", Type = FieldType.Textbox)]
[FieldDefinition(2, Label = "Url Base", Type = FieldType.Textbox, Advanced = true, HelpText = "Adds a prefix to the nzbget url, e.g. http://[host]:[port]/[urlBase]/jsonrpc")]
public string UrlBase { get; set; }
[FieldDefinition(3, Label = "Username", Type = FieldType.Textbox)]
public string Username { get; set; }
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string MovieCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing movies that released within the last 21 days")]
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing movies that released within the last 21 days")]
public int RecentMoviePriority { get; set; }
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing movies that released over 21 days ago")]
[FieldDefinition(7, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing movies that released over 21 days ago")]
public int OlderMoviePriority { get; set; }
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)]
[FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; }
[FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NZBGet version 16.0")]
[FieldDefinition(9, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NZBGet version 16.0")]
public bool AddPaused { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -25,8 +25,9 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService,
Logger logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, logger)
: base(httpClient, configService, namingConfigService, diskProvider, remotePathMappingService, nzbValidationService, logger)
{
_proxy = proxy;
}
@@ -115,17 +116,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
private IEnumerable<DownloadClientItem> GetHistory()
{
SabnzbdHistory sabHistory;
try
{
sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings.MovieCategory, Settings);
}
catch (DownloadClientException ex)
{
_logger.Error(ex, ex.Message);
return Enumerable.Empty<DownloadClientItem>();
}
var sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings.MovieCategory, Settings);
var historyItems = new List<DownloadClientItem>();
@@ -191,6 +182,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
}
}
historyItems.Add(historyItem);
}
@@ -327,6 +319,11 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
private Version ParseVersion(string version)
{
if (version.IsNullOrWhiteSpace())
{
return null;
}
var parsed = VersionRegex.Match(version);
int major;
@@ -364,7 +361,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
if (version == null)
{
return new ValidationFailure("Version", "Unknown Version: " + version);
return new ValidationFailure("Version", "Unknown Version: " + rawVersion);
}
if (rawVersion.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
@@ -424,7 +421,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
return new NzbDroneValidationFailure("", "Disable 'Check before download' option in SABnzbd")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings, "config/switches/"),
DetailedDescription = "Using Check before download affects Radarr ability to track new downloads. Also SABnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective."
};
}
@@ -443,7 +440,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
return new NzbDroneValidationFailure("MovieCategory", "Enable Job folders")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings, "config/categories/"),
DetailedDescription = "Radarr prefers each download to have a separate folder. With * appended to the Folder/Path SABnzbd will not create these job folders. Go to SABnzbd to fix it."
};
}
@@ -454,7 +451,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
return new NzbDroneValidationFailure("MovieCategory", "Category does not exist")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings, "config/categories/"),
DetailedDescription = "The category you entered doesn't exist in SABnzbd. Go to SABnzbd to create it."
};
}
@@ -463,7 +460,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
return new NzbDroneValidationFailure("MovieCategory", "Disable TV Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings, "config/sorting/"),
DetailedDescription = "You must disable SABnzbd TV Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
};
}
@@ -471,7 +468,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
return new NzbDroneValidationFailure("MovieCategory", "Disable Movie Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings, "config/sorting/"),
DetailedDescription = "You must disable SABnzbd Movie Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
};
}
@@ -479,7 +476,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
return new NzbDroneValidationFailure("MovieCategory", "Disable Date Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
InfoLink = _proxy.GetBaseUrl(Settings, "config/sorting/"),
DetailedDescription = "You must disable SABnzbd Date Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
};
}

View File

@@ -11,6 +11,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public interface ISabnzbdProxy
{
string GetBaseUrl(SabnzbdSettings settings, string relativePath = null);
SabnzbdAddResponse DownloadNzb(byte[] nzbData, string filename, string category, int priority, SabnzbdSettings settings);
void RemoveFrom(string source, string id,bool deleteData, SabnzbdSettings settings);
string GetVersion(SabnzbdSettings settings);
@@ -32,6 +33,14 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
_logger = logger;
}
public string GetBaseUrl(SabnzbdSettings settings, string relativePath = null)
{
var baseUrl = HttpRequestBuilder.BuildBaseUrl(settings.UseSsl, settings.Host, settings.Port, settings.UrlBase);
baseUrl = HttpUri.CombinePath(baseUrl, relativePath);
return baseUrl;
}
public SabnzbdAddResponse DownloadNzb(byte[] nzbData, string filename, string category, int priority, SabnzbdSettings settings)
{
var request = BuildRequest("addfile", settings).Post();
@@ -140,10 +149,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
private HttpRequestBuilder BuildRequest(string mode, SabnzbdSettings settings)
{
var baseUrl = string.Format(@"{0}://{1}:{2}/api",
settings.UseSsl ? "https" : "http",
settings.Host,
settings.Port);
var baseUrl = GetBaseUrl(settings, "api");
var requestBuilder = new HttpRequestBuilder(baseUrl)
.Accept(HttpAccept.Json)

View File

@@ -1,4 +1,5 @@
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -11,6 +12,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.Port).InclusiveBetween(1, 65535);
RuleFor(c => c.UrlBase).ValidUrlBase().When(c => c.UrlBase.IsNotNullOrWhiteSpace());
RuleFor(c => c.ApiKey).NotEmpty()
.WithMessage("API Key is required when username/password are not configured")
@@ -49,25 +51,28 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)]
public int Port { get; set; }
[FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox)]
[FieldDefinition(2, Label = "Url Base", Type = FieldType.Textbox, Advanced = true, HelpText = "Adds a prefix to the Sabnzbd url, e.g. http://[host]:[port]/[urlBase]/api")]
public string UrlBase { get; set; }
[FieldDefinition(3, Label = "API Key", Type = FieldType.Textbox)]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Username", Type = FieldType.Textbox)]
[FieldDefinition(4, Label = "Username", Type = FieldType.Textbox)]
public string Username { get; set; }
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
[FieldDefinition(5, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string MovieCategory { get; set; }
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing movies that released within the last 21 days")]
[FieldDefinition(7, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing movies that released within the last 21 days")]
public int RecentMoviePriority { get; set; }
[FieldDefinition(7, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing movies that released over 21 days ago")]
[FieldDefinition(8, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing movies that released over 21 days ago")]
public int OlderMoviePriority { get; set; }
[FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox)]
[FieldDefinition(9, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; }
public NzbDroneValidationResult Validate()

View File

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

View File

@@ -0,0 +1,45 @@
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.Download
{
public interface IValidateNzbs
{
void Validate(string filename, byte[] fileContent);
}
public class NzbValidationService : IValidateNzbs
{
public void Validate(string filename, byte[] fileContent)
{
var reader = new StreamReader(new MemoryStream(fileContent));
using (var xmlTextReader = XmlReader.Create(reader, new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore, IgnoreComments = true }))
{
var xDoc = XDocument.Load(xmlTextReader);
var nzb = xDoc.Root;
if (nzb == null)
{
throw new InvalidNzbException("Invalid NZB: No Root element [{0}]", filename);
}
if (!nzb.Name.LocalName.Equals("nzb"))
{
throw new InvalidNzbException("Invalid NZB: Unexpected root element. Expected 'nzb' found '{0}' [{1}]", nzb.Name.LocalName, filename);
}
var ns = nzb.Name.Namespace;
var files = nzb.Elements(ns + "file").ToList();
if (files.Empty())
{
throw new InvalidNzbException("Invalid NZB: No files [{0}]", filename);
}
}
}
}
}

View File

@@ -17,16 +17,19 @@ namespace NzbDrone.Core.Download
where TSettings : IProviderConfig, new()
{
protected readonly IHttpClient _httpClient;
private readonly IValidateNzbs _nzbValidationService;
protected UsenetClientBase(IHttpClient httpClient,
IConfigService configService,
INamingConfigService namingConfigService,
IDiskProvider diskProvider,
IRemotePathMappingService remotePathMappingService,
IValidateNzbs nzbValidationService,
Logger logger)
: base(configService, namingConfigService, diskProvider, remotePathMappingService, logger)
{
_httpClient = httpClient;
_nzbValidationService = nzbValidationService;
}
public override DownloadProtocol Protocol => DownloadProtocol.Usenet;
@@ -66,6 +69,8 @@ namespace NzbDrone.Core.Download
throw new ReleaseDownloadException(remoteMovie.Release, "Downloading nzb failed", ex);
}
_nzbValidationService.Validate(filename, nzbData);
_logger.Info("Adding report [{0}] to the queue.", remoteMovie.Release.Title);
return AddFromNzbFile(remoteMovie, filename, nzbData);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -102,122 +102,156 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFile)
{
if (!Settings.MovieMetadata)
{
return null;
}
_logger.Debug("Generating Movie Metadata for: {0}", Path.Combine(movie.Path, movieFile.RelativePath));
var watched = GetExistingWatchedStatus(movie, movieFile.RelativePath);
var xmlResult = string.Empty;
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = false;
using (var xw = XmlWriter.Create(sb, xws))
if (Settings.MovieMetadata)
{
var doc = new XDocument();
var image = movie.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
_logger.Debug("Generating Movie Metadata for: {0}", Path.Combine(movie.Path, movieFile.RelativePath));
var watched = GetExistingWatchedStatus(movie, movieFile.RelativePath);
var details = new XElement("movie");
var sb = new StringBuilder();
var xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Indent = false;
details.Add(new XElement("title", movie.Title));
if (movie.Ratings != null && movie.Ratings.Votes > 0)
using (var xw = XmlWriter.Create(sb, xws))
{
details.Add(new XElement("rating", movie.Ratings.Value));
}
var doc = new XDocument();
var thumbnail = movie.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot);
var posters = movie.Images.Where(i => i.CoverType == MediaCoverTypes.Poster);
var fanarts = movie.Images.Where(i => i.CoverType == MediaCoverTypes.Fanart);
details.Add(new XElement("plot", movie.Overview));
details.Add(new XElement("id", movie.ImdbId));
details.Add(new XElement("year", movie.Year));
var details = new XElement("movie");
if (movie.InCinemas.HasValue)
{
details.Add(new XElement("premiered", movie.InCinemas.Value.ToString("yyyy-MM-dd")));
}
details.Add(new XElement("title", movie.Title));
foreach (var genre in movie.Genres)
{
details.Add(new XElement("genre", genre));
}
details.Add(new XElement("studio", movie.Studio));
if (image == null)
{
details.Add(new XElement("thumb"));
}
else
{
details.Add(new XElement("thumb", image.Url));
}
details.Add(new XElement("watched", watched));
if (movieFile.MediaInfo != null)
{
var sceneName = movieFile.GetSceneOrFileName();
var fileInfo = new XElement("fileinfo");
var streamDetails = new XElement("streamdetails");
var video = new XElement("video");
video.Add(new XElement("aspect", (float)movieFile.MediaInfo.Width / (float)movieFile.MediaInfo.Height));
video.Add(new XElement("bitrate", movieFile.MediaInfo.VideoBitrate));
video.Add(new XElement("codec", MediaInfoFormatter.FormatVideoCodec(movieFile.MediaInfo, sceneName)));
video.Add(new XElement("framerate", movieFile.MediaInfo.VideoFps));
video.Add(new XElement("height", movieFile.MediaInfo.Height));
video.Add(new XElement("scantype", movieFile.MediaInfo.ScanType));
video.Add(new XElement("width", movieFile.MediaInfo.Width));
if (movieFile.MediaInfo.RunTime != null)
if (movie.Ratings != null && movie.Ratings.Votes > 0)
{
video.Add(new XElement("duration", movieFile.MediaInfo.RunTime.TotalMinutes));
video.Add(new XElement("durationinseconds", movieFile.MediaInfo.RunTime.TotalSeconds));
details.Add(new XElement("rating", movie.Ratings.Value));
}
streamDetails.Add(video);
details.Add(new XElement("plot", movie.Overview));
details.Add(new XElement("id", movie.ImdbId));
var audio = new XElement("audio");
audio.Add(new XElement("bitrate", movieFile.MediaInfo.AudioBitrate));
audio.Add(new XElement("channels", movieFile.MediaInfo.AudioChannels));
audio.Add(new XElement("codec", MediaInfoFormatter.FormatAudioCodec(movieFile.MediaInfo, sceneName)));
audio.Add(new XElement("language", movieFile.MediaInfo.AudioLanguages));
streamDetails.Add(audio);
if (movieFile.MediaInfo.Subtitles != null && movieFile.MediaInfo.Subtitles.Length > 0)
if (movie.ImdbId.IsNotNullOrWhiteSpace())
{
var subtitle = new XElement("subtitle");
subtitle.Add(new XElement("language", movieFile.MediaInfo.Subtitles));
streamDetails.Add(subtitle);
var imdbId = new XElement("uniqueid", movie.ImdbId);
imdbId.SetAttributeValue("type", "imdb");
imdbId.SetAttributeValue("default", true);
details.Add(imdbId);
}
fileInfo.Add(streamDetails);
details.Add(fileInfo);
var uniqueId = new XElement("uniqueid", movie.TmdbId);
uniqueId.SetAttributeValue("type", "tmdb");
details.Add(uniqueId);
details.Add(new XElement("year", movie.Year));
if (movie.InCinemas.HasValue)
{
details.Add(new XElement("premiered", movie.InCinemas.Value.ToString("yyyy-MM-dd")));
}
foreach (var genre in movie.Genres)
{
details.Add(new XElement("genre", genre));
}
details.Add(new XElement("studio", movie.Studio));
if (thumbnail == null)
{
details.Add(new XElement("thumb"));
}
else
{
details.Add(new XElement("thumb", thumbnail.Url));
}
foreach (var poster in posters)
{
if (poster != null && poster.Url != null)
{
details.Add(new XElement("thumb", new XAttribute("aspect", "poster"), poster.Url));
}
}
if (fanarts.Count() > 0)
{
var fanartElement = new XElement("fanart");
foreach (var fanart in fanarts)
{
if (fanart != null && fanart.Url != null)
{
fanartElement.Add(new XElement("thumb", fanart.Url));
}
}
details.Add(fanartElement);
}
details.Add(new XElement("watched", watched));
if (movieFile.MediaInfo != null)
{
var sceneName = movieFile.GetSceneOrFileName();
var fileInfo = new XElement("fileinfo");
var streamDetails = new XElement("streamdetails");
var video = new XElement("video");
video.Add(new XElement("aspect", (float)movieFile.MediaInfo.Width / (float)movieFile.MediaInfo.Height));
video.Add(new XElement("bitrate", movieFile.MediaInfo.VideoBitrate));
video.Add(new XElement("codec", MediaInfoFormatter.FormatVideoCodec(movieFile.MediaInfo, sceneName)));
video.Add(new XElement("framerate", movieFile.MediaInfo.VideoFps));
video.Add(new XElement("height", movieFile.MediaInfo.Height));
video.Add(new XElement("scantype", movieFile.MediaInfo.ScanType));
video.Add(new XElement("width", movieFile.MediaInfo.Width));
if (movieFile.MediaInfo.RunTime != null)
{
video.Add(new XElement("duration", movieFile.MediaInfo.RunTime.TotalMinutes));
video.Add(new XElement("durationinseconds", movieFile.MediaInfo.RunTime.TotalSeconds));
}
streamDetails.Add(video);
var audio = new XElement("audio");
audio.Add(new XElement("bitrate", movieFile.MediaInfo.AudioBitrate));
audio.Add(new XElement("channels", movieFile.MediaInfo.AudioChannels));
audio.Add(new XElement("codec", MediaInfoFormatter.FormatAudioCodec(movieFile.MediaInfo, sceneName)));
audio.Add(new XElement("language", movieFile.MediaInfo.AudioLanguages));
streamDetails.Add(audio);
if (movieFile.MediaInfo.Subtitles != null && movieFile.MediaInfo.Subtitles.Length > 0)
{
var subtitle = new XElement("subtitle");
subtitle.Add(new XElement("language", movieFile.MediaInfo.Subtitles));
streamDetails.Add(subtitle);
}
fileInfo.Add(streamDetails);
details.Add(fileInfo);
}
doc.Add(details);
doc.Save(xw);
xmlResult += doc.ToString();
xmlResult += Environment.NewLine;
}
doc.Add(details);
doc.Save(xw);
xmlResult += doc.ToString();
}
if (Settings.MovieMetadataURL)
{
xmlResult += "https://www.themoviedb.org/movie/" + movie.TmdbId;
xmlResult += Environment.NewLine;
xmlResult += "https://www.imdb.com/title/" + movie.ImdbId;
xmlResult += Environment.NewLine;
}
var metadataFileName = GetMovieMetadataFilename(movieFile.RelativePath);
if (Settings.UseMovieNfo)
{
metadataFileName = "movie.nfo";
}
return new MetadataFileResult(metadataFileName, xmlResult.Trim(Environment.NewLine.ToCharArray()));
return xmlResult == string.Empty ? null : new MetadataFileResult(metadataFileName, xmlResult.Trim(Environment.NewLine.ToCharArray()));
}
public override List<ImageFileResult> MovieImages(Movie movie)
@@ -243,7 +277,14 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
private string GetMovieMetadataFilename(string movieFilePath)
{
return Path.ChangeExtension(movieFilePath, "nfo");
if (Settings.UseMovieNfo)
{
return Path.Combine(Path.GetDirectoryName(movieFilePath), "movie.nfo");
}
else
{
return Path.ChangeExtension(movieFilePath, "nfo");
}
}
private bool GetExistingWatchedStatus(Movie movie, string movieFilePath)

View File

@@ -19,6 +19,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
public XbmcMetadataSettings()
{
MovieMetadata = true;
MovieMetadataURL = true;
MovieImages = true;
UseMovieNfo = false;
}
@@ -26,10 +27,13 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
[FieldDefinition(0, Label = "Movie Metadata", Type = FieldType.Checkbox)]
public bool MovieMetadata { get; set; }
[FieldDefinition(1, Label = "Movie Images", Type = FieldType.Checkbox)]
[FieldDefinition(1, Label = "Movie Metadata URL", Type = FieldType.Checkbox, HelpText = "Radarr will write the tmdb/imdb url in the .nfo file")]
public bool MovieMetadataURL { get; set; }
[FieldDefinition(2, Label = "Movie Images", Type = FieldType.Checkbox)]
public bool MovieImages { get; set; }
[FieldDefinition(2, Label = "Use Movie.nfo", Type = FieldType.Checkbox, HelpText = "Radarr will write metadata to movie.nfo instead of the default <movie-filename>.nfo")]
[FieldDefinition(3, Label = "Use Movie.nfo", Type = FieldType.Checkbox, HelpText = "Radarr will write metadata to movie.nfo instead of the default <movie-filename>.nfo")]
public bool UseMovieNfo { get; set; }
public bool IsValid => true;

View File

@@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if !LIBRARY
using NzbDrone.Common.EnsureThat;
#endif
namespace NzbDrone.Core
{
@@ -10,8 +12,9 @@ namespace NzbDrone.Core
{
public static string WithDefault(this string actual, object defaultValue)
{
#if !LIBRARY
Ensure.That(defaultValue, () => defaultValue).IsNotNull();
#endif
if (string.IsNullOrWhiteSpace(actual))
{
return defaultValue.ToString();

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
using (var mapper = _database.GetDataMapper())
{
var usedTags = new[] {"Movies", "Notifications", "DelayProfiles", "Restrictions"}
var usedTags = new[] {"Movies", "Notifications", "DelayProfiles", "Restrictions", "NetImport"}
.SelectMany(v => GetUsedTags(v, mapper))
.Distinct()
.ToArray();

View File

@@ -16,11 +16,11 @@ namespace NzbDrone.Core.Indexers.IPTorrents
{
RuleFor(c => c.BaseUrl).ValidRootUrl();
RuleFor(c => c.BaseUrl).Matches(@"/rss\?.+$");
RuleFor(c => c.BaseUrl).Matches(@"(?:/|t\.)rss\?.+$");
RuleFor(c => c.BaseUrl).Matches(@"/rss\?.+;download(?:;|$)")
RuleFor(c => c.BaseUrl).Matches(@"(?:/|t\.)rss\?.+;download(?:;|$)")
.WithMessage("Use Direct Download Url (;download)")
.When(v => v.BaseUrl.IsNotNullOrWhiteSpace() && Regex.IsMatch(v.BaseUrl, @"/rss\?.+$"));
.When(v => v.BaseUrl.IsNotNullOrWhiteSpace() && Regex.IsMatch(v.BaseUrl, @"(?:/|t\.)rss\?.+$"));
}
}

View File

@@ -8,7 +8,7 @@ namespace NzbDrone.Core.Indexers
{
private static readonly Regex ReplaceEntitiesRegex = new Regex("&[a-z]+;", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ReplaceUnicodeRegex = new Regex(@"[^\x09\x0A\x0D\x20-\xD7FF\xE000-\xFFFD\x10000-x10FFFF]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ReplaceUnicodeRegex = new Regex(@"[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static string ReplaceEntities(string content)
{

View File

@@ -71,7 +71,6 @@ namespace NzbDrone.Core.Jobs
var defaultTasks = new[]
{
new ScheduledTask{ Interval = 1, TypeName = typeof(CheckForFinishedDownloadCommand).FullName},
new ScheduledTask{ Interval = 1*60, TypeName = typeof(PreDBSyncCommand).FullName},
new ScheduledTask{ Interval = 5, TypeName = typeof(MessagingCleanupCommand).FullName},
new ScheduledTask{ Interval = updateInterval, TypeName = typeof(ApplicationUpdateCommand).FullName},
@@ -98,6 +97,12 @@ namespace NzbDrone.Core.Jobs
Interval = _configService.DownloadedMoviesScanInterval,
TypeName = typeof(DownloadedMoviesScanCommand).FullName
},
new ScheduledTask
{
Interval = Math.Max(_configService.CheckForFinishedDownloadInterval, 1),
TypeName = typeof(CheckForFinishedDownloadCommand).FullName
},
};
var currentTasks = _scheduledTaskRepository.All().ToList();
@@ -184,7 +189,10 @@ namespace NzbDrone.Core.Jobs
var netImport = _scheduledTaskRepository.GetDefinition(typeof(NetImportSyncCommand));
netImport.Interval = _configService.NetImportSyncInterval;
_scheduledTaskRepository.UpdateMany(new List<ScheduledTask> { rss, downloadedMovies, netImport });
var checkForFinishedDownloads = _scheduledTaskRepository.GetDefinition(typeof(CheckForFinishedDownloadCommand));
checkForFinishedDownloads.Interval = _configService.CheckForFinishedDownloadInterval;
_scheduledTaskRepository.UpdateMany(new List<ScheduledTask> { rss, downloadedMovies, netImport, checkForFinishedDownloads });
}
}
}

View File

@@ -23,7 +23,7 @@ namespace NzbDrone.Core.MediaCover
public class MediaCoverService :
IHandleAsync<MovieUpdatedEvent>,
IHandleAsync<MovieAddedEvent>,
//IHandleAsync<MovieAddedEvent>,
IHandleAsync<MovieDeletedEvent>,
IExecute<EnsureMediaCoversCommand>,
IMapCoversToLocal
@@ -208,7 +208,7 @@ namespace NzbDrone.Core.MediaCover
public void HandleAsync(MovieAddedEvent message)
{
//EnsureCovers(message.Movie);
_commandQueue.Push(new EnsureMediaCoversCommand(message.Movie.Id));
//_commandQueue.Push(new EnsureMediaCoversCommand(message.Movie.Id));
//_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Movie));
}

View File

@@ -701,6 +701,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
newMovie.Monitored = movie.Monitored;
newMovie.MovieFile = movie.MovieFile;
newMovie.MinimumAvailability = movie.MinimumAvailability;
newMovie.Tags = movie.Tags;
return newMovie;
}

View File

@@ -118,6 +118,7 @@ namespace NzbDrone.Core.NetImport
m.ProfileId = ((NetImportDefinition) Definition).ProfileId;
m.Monitored = ((NetImportDefinition) Definition).ShouldMonitor;
m.MinimumAvailability = ((NetImportDefinition) Definition).MinimumAvailability;
m.Tags = ((NetImportDefinition) Definition).Tags;
return m;
}).ToList();
}
@@ -170,6 +171,5 @@ namespace NzbDrone.Core.NetImport
return null;
}
}
}

View File

@@ -1,4 +1,5 @@
using Marr.Data;
using System.Collections.Generic;
using Marr.Data;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Movies;
@@ -7,6 +8,11 @@ namespace NzbDrone.Core.NetImport
{
public class NetImportDefinition : ProviderDefinition
{
public NetImportDefinition()
{
Tags = new HashSet<int>();
}
public bool Enabled { get; set; }
public bool EnableAuto { get; set; }
public bool ShouldMonitor { get; set; }
@@ -15,5 +21,6 @@ namespace NzbDrone.Core.NetImport
public LazyLoaded<Profile> Profile { get; set; }
public string RootFolderPath { get; set; }
public override bool Enable => Enabled;
public HashSet<int> Tags { get; set; }
}
}

View File

@@ -40,12 +40,14 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Radarr_Movie_ImdbId", movie.ImdbId ?? string.Empty);
environmentVariables.Add("Radarr_Movie_TmdbId", movie.TmdbId.ToString());
environmentVariables.Add("Radarr_Release_Title", remoteMovie.Release.Title);
environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer);
environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer ?? string.Empty);
environmentVariables.Add("Radarr_Release_Size", remoteMovie.Release.Size.ToString());
environmentVariables.Add("Radarr_Release_ReleaseGroup", remoteMovie.ParsedMovieInfo.ReleaseGroup ?? string.Empty);
environmentVariables.Add("Radarr_Release_Quality", quality.Quality.Name);
environmentVariables.Add("Radarr_Release_QualityVersion", quality.Revision.Version.ToString());
environmentVariables.Add("Radarr_IndexerFlags", remoteMovie.Release.IndexerFlags.ToString());
environmentVariables.Add("Radarr_Download_Client", message.DownloadClient ?? string.Empty);
environmentVariables.Add("Radarr_Download_Id", message.DownloadId ?? string.Empty);
ExecuteScript(environmentVariables);
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using FluentValidation.Results;
using NLog;
using NzbDrone.Core.Movies;
namespace NzbDrone.Core.Notifications.Gotify
{
public class Gotify : NotificationBase<GotifySettings>
{
private readonly IGotifyProxy _proxy;
private readonly Logger _logger;
public Gotify(IGotifyProxy proxy, Logger logger)
{
_proxy = proxy;
_logger = logger;
}
public override string Name => "Gotify";
public override string Link => "https://gotify.net/";
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Movie Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Movie Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override bool SupportsOnRename => false;
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
try
{
const string title = "Test Notification";
const string body = "This is a test message from Radarr";
_proxy.SendNotification(title, body, Settings);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
failures.Add(new ValidationFailure("", "Unable to send test message"));
}
return new ValidationResult(failures);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace NzbDrone.Core.Notifications.Gotify
{
public enum GotifyPriority
{
Min = 0,
Low = 2,
Normal = 5,
High = 8
}
}

View File

@@ -0,0 +1,26 @@
using RestSharp;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.Notifications.Gotify
{
public interface IGotifyProxy
{
void SendNotification(string title, string message, GotifySettings settings);
}
public class GotifyProxy : IGotifyProxy
{
public void SendNotification(string title, string message, GotifySettings settings)
{
var client = RestClientFactory.BuildClient(settings.Server);
var request = new RestRequest("message", Method.POST);
request.AddQueryParameter("token", settings.AppToken);
request.AddParameter("title", title);
request.AddParameter("message", message);
request.AddParameter("priority", settings.Priority);
client.ExecuteAndValidate(request);
}
}
}

View File

@@ -0,0 +1,40 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Gotify
{
public class GotifySettingsValidator : AbstractValidator<GotifySettings>
{
public GotifySettingsValidator()
{
RuleFor(c => c.Server).IsValidUrl();
RuleFor(c => c.AppToken).NotEmpty();
}
}
public class GotifySettings : IProviderConfig
{
private static readonly GotifySettingsValidator Validator = new GotifySettingsValidator();
public GotifySettings()
{
Priority = 5;
}
[FieldDefinition(0, Label = "Gotify Server", HelpText = "Gotify server URL, including http(s):// and port if needed")]
public string Server { get; set; }
[FieldDefinition(1, Label = "App Token", HelpText = "The Application Token generated by Gotify")]
public string AppToken { get; set; }
[FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")]
public int Priority { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace NzbDrone.Core.Notifications.Gotify
{
public class InvalidResponseException : Exception
{
public InvalidResponseException()
{
}
public InvalidResponseException(string message) : base(message)
{
}
}
}

View File

@@ -1,4 +1,4 @@
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Movies;
@@ -9,7 +9,9 @@ namespace NzbDrone.Core.Notifications
public string Message { get; set; }
public Movie Movie { get; set; }
public RemoteMovie RemoteMovie { get; set; }
public QualityModel Quality { get; set; }
public QualityModel Quality { get; set; }
public string DownloadClient { get; set; }
public string DownloadId { get; set; }
public override string ToString()
{

View File

@@ -37,7 +37,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
if (Settings.UpdateLibrary)
{
_mediaBrowserService.UpdateMovies(Settings, message.Movie);
_mediaBrowserService.UpdateMovies(Settings, message.Movie, "Created");
}
}
@@ -45,7 +45,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
{
if (Settings.UpdateLibrary)
{
_mediaBrowserService.UpdateMovies(Settings, movie);
_mediaBrowserService.UpdateMovies(Settings, movie, "Modified");
}
}

View File

@@ -31,11 +31,23 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
ProcessRequest(request, settings);
}
public void UpdateMovies(MediaBrowserSettings settings, string imdbid)
public void UpdateMovies(MediaBrowserSettings settings, string moviePath, string updateType)
{
var path = string.Format("/Library/Movies/Updated?ImdbId={0}", imdbid);
var path = "/Library/Media/Updated";
var request = BuildRequest(path, settings);
request.Headers.Add("Content-Length", "0");
request.Headers.ContentType = "application/json";
request.SetContent(new
{
Updates = new[]
{
new
{
Path = moviePath,
UpdateType = updateType
}
}
}.ToJson());
ProcessRequest(request, settings);
}

View File

@@ -10,7 +10,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public interface IMediaBrowserService
{
void Notify(MediaBrowserSettings settings, string title, string message);
void UpdateMovies(MediaBrowserSettings settings, Movie movie);
void UpdateMovies(MediaBrowserSettings settings, Movie movie, string updateType);
ValidationFailure Test(MediaBrowserSettings settings);
}
@@ -30,9 +30,9 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
_proxy.Notify(settings, title, message);
}
public void UpdateMovies(MediaBrowserSettings settings, Movie movie)
public void UpdateMovies(MediaBrowserSettings settings, Movie movie, string updateType)
{
_proxy.UpdateMovies(settings, movie.ImdbId);
_proxy.UpdateMovies(settings, movie.Path, updateType);
}

View File

@@ -72,7 +72,9 @@ namespace NzbDrone.Core.Notifications
Message = GetMessage(message.Movie.Movie, message.Movie.ParsedMovieInfo.Quality),
Quality = message.Movie.ParsedMovieInfo.Quality,
Movie = message.Movie.Movie,
RemoteMovie = message.Movie
RemoteMovie = message.Movie,
DownloadClient = message.DownloadClient,
DownloadId = message.DownloadId
};
foreach (var notification in _notificationFactory.OnGrabEnabled())

View File

@@ -146,9 +146,12 @@
<Compile Include="Datastore\Migration\144_add_cookies_to_indexer_status.cs" />
<Compile Include="Datastore\Migration\149_convert_regex_required_tags.cs" />
<Compile Include="Datastore\Migration\150_fix_format_tags_double_underscore.cs" />
<Compile Include="Datastore\Migration\151_add_tags_to_net_import.cs" />
<Compile Include="DecisionEngine\Specifications\CustomFormatAllowedByProfileSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\MaximumSizeSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\RequiredIndexerFlagsSpecification.cs" />
<Compile Include="Download\InvalidNzbException.cs" />
<Compile Include="Download\NzbValidationService.cs" />
<Compile Include="Extras\Metadata\Consumers\Xbmc\XbmcNfoDetector.cs" />
<Compile Include="Extras\Others\OtherExtraFileRenamer.cs" />
<Compile Include="HealthCheck\Checks\PTPOldSettingsCheck.cs" />
@@ -923,6 +926,11 @@
<Compile Include="Extras\Metadata\MetadataType.cs" />
<Compile Include="MetadataSource\TmdbConfigurationService.cs" />
<Compile Include="NetImport\NetImportSyncCommand.cs" />
<Compile Include="Notifications\Gotify\InvalidResponseException.cs" />
<Compile Include="Notifications\Gotify\Gotify.cs" />
<Compile Include="Notifications\Gotify\GotifyPriority.cs" />
<Compile Include="Notifications\Gotify\GotifyService.cs" />
<Compile Include="Notifications\Gotify\GotifySettings.cs" />
<Compile Include="Notifications\Join\JoinAuthException.cs" />
<Compile Include="Notifications\Join\JoinInvalidDeviceException.cs" />
<Compile Include="Notifications\Join\JoinResponseModel.cs" />
@@ -1328,4 +1336,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@@ -13,10 +13,10 @@ namespace NzbDrone.Core.Parser
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(LanguageParser));
private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_)(?<italian>\b(?:ita|italian)\b)|(?<german>german\b|videomann)|(?<flemish>flemish)|(?<greek>greek)|(?<french>(?:\W|_)(?:FR|VOSTFR|VO|VFF|VFQ|VF2|TRUEFRENCH)(?:\W|_))|(?<russian>\brus\b)|(?<dutch>nl\W?subs?)|(?<hungarian>\b(?:HUNDUB|HUN)\b)|(?<hebrew>\bHebDub\b)|(?<czech>\bCZ|SK\b)",
private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_|^)(?<italian>\b(?:ita|italian)\b)|(?<german>german\b|videomann)|(?<flemish>flemish)|(?<greek>greek)|(?<french>(?:\W|_)(?:FR|VOSTFR|VO|VFF|VFQ|VF2|TRUEFRENCH)(?:\W|_))|(?<russian>\brus\b)|(?<dutch>nl\W?subs?)|(?<hungarian>\b(?:HUNDUB|HUN)\b)|(?<hebrew>\bHebDub\b)|(?<czech>\b(?:CZ|SK)\b)",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SubtitleLanguageRegex = new Regex(".+?[-_. ](?<iso_code>[a-z]{2,3})$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex SubtitleLanguageRegex = new Regex(".+?[-_. ](?<iso_code>[a-z]{2,3})(?:[-_. ]forced)?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static List<Language> ParseLanguages(string title)
{
@@ -142,7 +142,9 @@ namespace NzbDrone.Core.Parser
{
try
{
#if !LIBRARY
Logger.Debug("Parsing language from subtitle file: {0}", fileName);
#endif
var simpleFilename = Path.GetFileNameWithoutExtension(fileName);
var languageMatch = SubtitleLanguageRegex.Match(simpleFilename);
@@ -154,12 +156,15 @@ namespace NzbDrone.Core.Parser
return isoLanguage?.Language ?? Language.Unknown;
}
#if !LIBRARY
Logger.Debug("Unable to parse langauge from subtitle file: {0}", fileName);
#endif
}
catch (Exception ex)
{
#if !LIBRARY
Logger.Debug("Failed parsing langauge from subtitle file: {0}", fileName);
#endif
}
return Language.Unknown;

View File

@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Parser.Model
@@ -39,14 +38,39 @@ namespace NzbDrone.Core.Parser.Model
public int Year { get; set; }
public string ImdbId { get; set; }
public ParsedMovieInfo()
{
}
public override string ToString()
{
return string.Format("{0} - {1} {2}", MovieTitle, Year, Quality);
return String.Format("{0} - {1} {2}", MovieTitle, Year, Quality);
}
#if LIBRARY
public static ParsedMovieInfo ParseMovieInfo(string title)
{
var parsedMovie = Parser.ParseMovieTitle(title, false);
if (parsedMovie == null) return null;
parsedMovie.Languages = LanguageParser.ParseLanguages(parsedMovie.SimpleReleaseTitle);
parsedMovie.Quality = QualityParser.ParseQuality(parsedMovie.SimpleReleaseTitle);
if (parsedMovie.Edition.IsNullOrWhiteSpace())
{
parsedMovie.Edition = Parser.ParseEdition(parsedMovie.SimpleReleaseTitle);
}
parsedMovie.ReleaseGroup = Parser.ParseReleaseGroup(parsedMovie.SimpleReleaseTitle);
parsedMovie.ImdbId = Parser.ParseImdbId(parsedMovie.SimpleReleaseTitle);
parsedMovie.Languages =
LanguageParser.EnhanceLanguages(parsedMovie.SimpleReleaseTitle, parsedMovie.Languages);
parsedMovie.Quality.Quality = Qualities.Quality.FindByInfo(parsedMovie.Quality.Source, parsedMovie.Quality.Resolution,
parsedMovie.Quality.Modifier);
return parsedMovie;
}
#endif
}
}

View File

@@ -4,13 +4,15 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser.Model;
using NLog;
using NzbDrone.Common.Instrumentation;
#if !LIBRARY
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Movies;
using TinyIoC;
#endif
namespace NzbDrone.Core.Parser
{
@@ -21,7 +23,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex[] ReportMovieTitleRegex = new[]
{
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*\(?(?<edition>(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\)?.{1,3}(?<year>(1(8|9)|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*\(?\b(?<edition>(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\b\)?.{1,3}(?<year>(1(8|9)|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily!
@@ -86,9 +88,9 @@ namespace NzbDrone.Core.Parser
};
//Regex to detect whether the title was reversed.
private static readonly Regex ReversedTitleRegex = new Regex(@"[-._ ](p027|p0801|\d{2}E\d{2}S)[-._ ]", RegexOptions.Compiled);
private static readonly Regex ReversedTitleRegex = new Regex(@"(?:^|[-._ ])(p027|p0801)[-._ ]", RegexOptions.Compiled);
private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?<!^|\W\w\W)(a(?!$|\W\w\W)|an|the|and|or|of)(?:\b|_))|\W|_",
private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?<!^|[^a-zA-Z0-9_']\w[^a-zA-Z0-9_'])(a(?!$|[^a-zA-Z0-9_']\w[^a-zA-Z0-9_'])|an|the|and|or|of)(?:\b|_))|\W|_",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex FileExtensionRegex = new Regex(@"\.[a-z0-9]{2,4}$",
@@ -136,7 +138,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex ReportYearRegex = new Regex(@"^.*(?<year>(19|20)\d{2}).*$", RegexOptions.Compiled);
private static readonly Regex ReportEditionRegex = new Regex(@"(?<edition>(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\)?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ReportEditionRegex = new Regex(@"\b(?<edition>(((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final(?=(.(Cut|Edition|Version)))|Extended|Rogue|Special|Despecialized|\d{2,3}(th)?.Anniversary)(.(Cut|Edition|Version))?(.(Extended|Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit))?|((Uncensored|Remastered|Unrated|Uncut|IMAX|Fan.?Edit|Edition|Restored|((2|3|4)in1))))))\)?\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly string[] Numbers = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
private static Dictionary<String, String> _umlautMappings = new Dictionary<string, string>
@@ -463,27 +465,6 @@ namespace NzbDrone.Core.Parser
return title;
}
private static SeriesTitleInfo GetSeriesTitleInfo(string title)
{
var seriesTitleInfo = new SeriesTitleInfo();
seriesTitleInfo.Title = title;
var match = YearInTitleRegex.Match(title);
if (!match.Success)
{
seriesTitleInfo.TitleWithoutYear = title;
}
else
{
seriesTitleInfo.TitleWithoutYear = match.Groups["title"].Value;
seriesTitleInfo.Year = Convert.ToInt32(match.Groups["year"].Value);
}
return seriesTitleInfo;
}
private static ParsedMovieInfo ParseMovieMatchCollection(MatchCollection matchCollection)
{
if (!matchCollection[0].Groups["title"].Success || matchCollection[0].Groups["title"].Value == "(")

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Parser
// RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex SourceRegex = new Regex(@"\b(?:
(?<bluray>BluRay|Blu-Ray|HDDVD|BD|BDISO|BD25|BD50|BR.?DISK)|
(?<bluray>M?BluRay|Blu-Ray|HDDVD|BD|BDISO|BD25|BD50|BR.?DISK)|
(?<webdl>WEB[-_. ]DL|HDRIP|WEBDL|WebRip|Web-Rip|iTunesHD|WebHD|[. ]WEB[. ](?:[xh]26[45]|DD5[. ]1)|\d+0p[. ]WEB[. ])|
(?<hdtv>HDTV)|
(?<bdrip>BDRip)|(?<brrip>BRRip)|

View File

@@ -147,7 +147,7 @@ namespace NzbDrone.Core.Qualities
{
AllLookup[quality.Id] = quality;
}
#if !LIBRARY
DefaultQualityDefinitions = new HashSet<QualityDefinition>
{
new QualityDefinition(Quality.Unknown) { Weight = 1, MinSize = 0, MaxSize = 100 },
@@ -182,14 +182,16 @@ namespace NzbDrone.Core.Qualities
new QualityDefinition(Quality.BRDISK) { Weight = 25, MinSize = 0, MaxSize = null },
new QualityDefinition(Quality.RAWHD) { Weight = 26, MinSize = 0, MaxSize = null }
};
#endif
}
public static readonly List<Quality> All;
public static readonly Quality[] AllLookup;
#if !LIBRARY
public static readonly HashSet<QualityDefinition> DefaultQualityDefinitions;
#endif
public static Quality FindById(int id)
{
if (id == 0) return Unknown;

View File

@@ -90,6 +90,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogentriesNLog", "Logentrie
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CurlSharp", "ExternalModules\CurlSharp\CurlSharp\CurlSharp.csproj", "{74420A79-CC16-442C-8B1E-7C1B913844F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsingLibrary", "ParsingLibrary\ParsingLibrary.csproj", "{BAC762EF-4627-49C8-BC99-EB9D20682FA4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -276,6 +278,9 @@ Global
{74420A79-CC16-442C-8B1E-7C1B913844F0}.Mono|x86.Build.0 = Release|Any CPU
{74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|x86.ActiveCfg = Release|Any CPU
{74420A79-CC16-442C-8B1E-7C1B913844F0}.Release|x86.Build.0 = Release|Any CPU
{BAC762EF-4627-49C8-BC99-EB9D20682FA4}.Debug|x86.ActiveCfg = Debug|Any CPU
{BAC762EF-4627-49C8-BC99-EB9D20682FA4}.Mono|x86.ActiveCfg = Debug|Any CPU
{BAC762EF-4627-49C8-BC99-EB9D20682FA4}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,18 @@
using System;
using NLog;
namespace NzbDrone.Common.Instrumentation
{
public static class NzbDroneLogger
{
public static Logger GetLogger(Type type)
{
return LogManager.GetLogger(type.Name.Replace("NzbDrone.", ""));
}
public static Logger GetLogger(object obj)
{
return GetLogger(obj.GetType());
}
}
}

View File

@@ -0,0 +1,95 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE;DEBUG;NETSTANDARD;NETSTANDARD2_0;LIBRARY;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>TRACE;RELEASE;NETSTANDARD;NETSTANDARD2_0;LIBRARY</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\NzbDrone.Common\Exceptions\NzbDroneException.cs">
<Link>NzbDroneException.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Common\Extensions\DictionaryExtensions.cs">
<Link>DictionaryExtensions.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Common\Extensions\IEnumerableExtensions.cs">
<Link>IEnumerableExtensions.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Common\Extensions\Int64Extensions.cs">
<Link>Int64Extensions.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Common\Extensions\StringExtensions.cs">
<Link>StringExtensions.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\CustomFormats\CustomFormat.cs">
<Link>CustomFormat.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\CustomFormats\FormatTag.cs">
<Link>FormatTag.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Datastore\IEmbeddedDocument.cs">
<Link>IEmbeddedDocument.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Datastore\ModelBase.cs">
<Link>ModelBase.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Fluent.cs">
<Link>Fluent.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\MediaFiles\MediaFileExtensions.cs">
<Link>MediaFileExtensions.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\InvalidDateException.cs">
<Link>InvalidDateException.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\IsoLanguage.cs">
<Link>IsoLanguage.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\IsoLanguages.cs">
<Link>IsoLanguages.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\Language.cs">
<Link>Language.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\LanguageParser.cs">
<Link>LanguageParser.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\Model\ParsedMovieInfo.cs">
<Link>ParsedMovieInfo.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\Parser.cs">
<Link>Parser.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\QualityParser.cs">
<Link>QualityParser.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Parser\SceneChecker.cs">
<Link>SceneChecker.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Qualities\Quality.cs">
<Link>Quality.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Qualities\QualityModel.cs">
<Link>QualityModel.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Qualities\QualitySource.cs">
<Link>QualitySource.cs</Link>
</Compile>
<Compile Include="..\NzbDrone.Core\Qualities\Revision.cs">
<Link>Revision.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="NLog" Version="4.5.11" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
using System.IO;
namespace NzbDrone.Common.Extensions
{
public static class PathExtensions
{
public static bool ContainsInvalidPathChars(this string text)
{
return text.IndexOfAny(Path.GetInvalidPathChars()) >= 0;
}
}
}

View File

@@ -1,6 +1,5 @@
var Marionette = require('marionette');
var StatusModel = require('../System/StatusModel');
require('../Mixins/CopyToClipboard');
require('../Mixins/TagInput');
module.exports = Marionette.Layout.extend({
@@ -18,16 +17,21 @@ module.exports = Marionette.Layout.extend({
events : {
'click .x-includeUnmonitored' : '_updateUrl',
'click .x-premiersOnly' : '_updateUrl',
'click .x-ical-copy' : '_copyIcalToClipboard',
'itemAdded .x-tags' : '_updateUrl',
'itemRemoved .x-tags' : '_updateUrl'
},
onShow : function() {
this._updateUrl();
this.ui.icalCopy.copyToClipboard(this.ui.icalUrl);
this.ui.tags.tagInput({ allowNew: false });
},
_copyIcalToClipboard: function () {
this.ui.icalUrl.select();
document.execCommand("copy");
},
_updateUrl : function() {
var icalUrl = window.location.host + StatusModel.get('urlBase') + '/feed/calendar/Radarr.ics?';

View File

@@ -1,22 +0,0 @@
var $ = require('jquery');
var StatusModel = require('../System/StatusModel');
var ZeroClipboard = require('zero.clipboard');
var Messenger = require('../Shared/Messenger');
$.fn.copyToClipboard = function(input) {
ZeroClipboard.config({
swfPath : StatusModel.get('urlBase') + '/Content/zero.clipboard.swf'
});
var client = new ZeroClipboard(this);
client.on('ready', function(e) {
client.on('copy', function(e) {
e.clipboardData.setData("text/plain", input.val());
});
client.on('aftercopy', function() {
Messenger.show({ message : 'Copied text to clipboard' });
});
});
};

View File

@@ -43,6 +43,18 @@
</div>
</div>
</div>
<div class="form-group advanced-settings">
<label class="col-sm-3 control-label">Check For Finished Downloads Interval</label>
<div class="col-sm-1 col-sm-push-2 help-inline">
<i class="icon-radarr-form-info" title="Interval in minutes to query the download clients for finished downloads"/>
</div>
<div class="col-sm-2 col-sm-pull-1">
<input type="number" name="checkForFinishedDownloadInterval" class="form-control" />
</div>
</div>
</div>
</fieldset>

View File

@@ -4,8 +4,6 @@ var CommandController = require('../../Commands/CommandController');
var AsModelBoundView = require('../../Mixins/AsModelBoundView');
var AsValidatedView = require('../../Mixins/AsValidatedView');
require('../../Mixins/CopyToClipboard');
var view = Marionette.ItemView.extend({
template : 'Settings/General/GeneralViewTemplate',
@@ -14,6 +12,7 @@ var view = Marionette.ItemView.extend({
'change .x-proxy' : '_setProxyOptionsVisibility',
'change .x-ssl' : '_setSslOptionsVisibility',
'click .x-reset-api-key' : '_resetApiKey',
'click .x-copy-api-key' : '_copyApiKeyToClipboard',
'change .x-update-mechanism' : '_setScriptGroupVisibility'
},
@@ -57,11 +56,12 @@ var view = Marionette.ItemView.extend({
command : {
name : 'resetApiKey'
}
});
});
},
onShow : function() {
this.ui.copyApiKey.copyToClipboard(this.ui.apiKeyInput);
_copyApiKeyToClipboard : function() {
this.ui.apiKeyInput.select();
document.execCommand("copy");
},
_setAuthOptionsVisibility : function() {

View File

@@ -2,7 +2,7 @@
<legend>File Management</legend>
<div class="form-group">
<label class="col-sm-3 control-label">Ignore Deleted Movies</label>
<label class="col-sm-3 control-label">Unmonitor Deleted Movies</label>
<div class="col-sm-9">
<div class="input-group">

View File

@@ -89,6 +89,7 @@
<ul class="dropdown-menu">
{{> MovieTitleNamingPartial}}
{{> ReleaseYearNamingPartial}}
{{> TagsNamingPartial}}
{{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}
@@ -118,6 +119,7 @@
<ul class="dropdown-menu">
{{> MovieTitleNamingPartial}}
{{> ReleaseYearNamingPartial}}
{{> TagsNamingPartial}}
{{> QualityNamingPartial}}
{{> MediaInfoNamingPartial}}
{{> ReleaseGroupNamingPartial}}

View File

@@ -1,8 +0,0 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="absolute">Absolute</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="absolute">1</a></li>
<li><a href="#" data-token="absolute:00">01</a></li>
<li><a href="#" data-token="absolute:000">001</a></li>
</ul>
</li>

View File

@@ -1,9 +0,0 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="Air-Date">Air-Date</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="Air-Date">Air-Date</a></li>
<li><a href="#" data-token="Air Date">Air Date</a></li>
<li><a href="#" data-token="Air.Date">Air.Date</a></li>
<li><a href="#" data-token="Air_Date">Air_Date</a></li>
</ul>
</li>

View File

@@ -1,7 +0,0 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="episode">Episode</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="episode">1</a></li>
<li><a href="#" data-token="episode:00">01</a></li>
</ul>
</li>

View File

@@ -1,11 +0,0 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="Episode Title">Episode Title</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="Episode Title">Episode Title</a></li>
<li><a href="#" data-token="Episode.Title">Episode.Title</a></li>
<li><a href="#" data-token="Episode_Title">Episode_Title</a></li>
<li><a href="#" data-token="Episode CleanTitle">Episode CleanTitle</a></li>
<li><a href="#" data-token="Episode.CleanTitle">Episode.CleanTitle</a></li>
<li><a href="#" data-token="Episode_CleanTitle">Episode_CleanTitle</a></li>
</ul>
</li>

View File

@@ -1,7 +0,0 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="season">Season</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="season">1</a></li>
<li><a href="#" data-token="season:00">01</a></li>
</ul>
</li>

View File

@@ -1,11 +0,0 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="Series Title">Series Title</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="Series Title">Series Title</a></li>
<li><a href="#" data-token="Series.Title">Series.Title</a></li>
<li><a href="#" data-token="Series_Title">Series_Title</a></li>
<li><a href="#" data-token="Series CleanTitle">Series CleanTitle</a></li>
<li><a href="#" data-token="Series.CleanTitle">Series.CleanTitle</a></li>
<li><a href="#" data-token="Series_CleanTitle">Series_CleanTitle</a></li>
</ul>
</li>

View File

@@ -0,0 +1,8 @@
<li class="dropdown-submenu">
<a href="#" tabindex="-1" data-token="Tags">Tags</a>
<ul class="dropdown-menu">
<li><a href="#" data-token="Edition Tags">Edition Tags</a></li>
<li><a href="#" data-token="Edition.Tags">Edition.Tags</a></li>
<li><a href="#" data-token="Edition_Tags">Edition_Tags</a></li>
</ul>
</li>

View File

@@ -22,6 +22,7 @@ var view = Marionette.ItemView.extend({
profile : '.x-profile',
minimumAvailability : '.x-minimumavailability',
rootFolder : '.x-root-folder',
tags : '.x-tags'
},
events : {
@@ -53,6 +54,10 @@ var view = Marionette.ItemView.extend({
this.ui.rootFolder.val(defaultRoot);
}
}
this.ui.tags.tagInput({
model : this.model,
property : 'tags'
});
},
_onBeforeSave : function() {

View File

@@ -101,6 +101,14 @@
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Tags</label>
<div class="col-sm-5">
<input type="text" class="form-control x-tags">
</div>
</div>
{{formBuilder}}
</div>
</div>

View File

@@ -9,7 +9,7 @@ var view = Marionette.ItemView.extend({
slider : {
min : 0,
max : 200,
max : 400,
step : 0.1
},

View File

@@ -7,7 +7,7 @@
<span class="col-md-2 col-sm-3">
<input type="text" class="form-control" name="title">
</span>
<span class="col-md-4 col-sm-6">
<span class="col-md-5 col-sm-7">
<div class="x-slider"></div>
<div class="size-label-wrapper">
<div class="pull-left">

View File

@@ -29,7 +29,6 @@ require.config({
'messenger' : 'JsLibraries/messenger',
'jquery' : 'JsLibraries/jquery',
'typeahead' : 'JsLibraries/typeahead',
'zero.clipboard' : 'JsLibraries/zero.clipboard',
'libs' : 'JsLibraries/'
},

View File

@@ -11,7 +11,6 @@ require('jquery.knob');
require('jquery.easypiechart');
require('jquery.dotdotdot');
require('typeahead');
require('zero.clipboard');
/*Bootstrap*/
require('bootstrap');

View File

@@ -9,7 +9,7 @@ if [ -d "$TEST_DIR/_tests" ]; then
TEST_DIR="$TEST_DIR/_tests"
fi
NUNIT="$TEST_DIR/NUnit.ConsoleRunner.3.2.1/tools/nunit3-console.exe"
NUNIT="$TEST_DIR/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe"
NUNIT_COMMAND="$NUNIT"
NUNIT_PARAMS="--result=$TEST_DIR/reports/junit/results-$TYPE.xml;transform=.circleci/nunit3-junit.xslt --agents=12 --config=Debug"
@@ -17,7 +17,7 @@ if [ "$PLATFORM" = "Windows" ]; then
WHERE="$WHERE && cat != LINUX"
elif [ "$PLATFORM" = "Linux" ]; then
WHERE="$WHERE && cat != WINDOWS"
NUNIT_COMMAND="mono --debug --runtime=v4.0 $NUNIT"
NUNIT_COMMAND="mono --debug $NUNIT"
elif [ "$PLATFORM" = "Mac" ]; then
WHERE="$WHERE && cat != WINDOWS"
NUNIT_COMMAND="mono --debug --runtime=v4.0 $NUNIT"