mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-17 21:26:22 -04:00
Compare commits
47 Commits
v0.2.0.129
...
v0.2.0.134
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
002f84c58b | ||
|
|
3f26dae02b | ||
|
|
7756b03555 | ||
|
|
5faaffc9c6 | ||
|
|
7a43bf3f60 | ||
|
|
84fab25af7 | ||
|
|
52520e356d | ||
|
|
cc44d022b3 | ||
|
|
f411903e90 | ||
|
|
9985554dcb | ||
|
|
f8c009a348 | ||
|
|
da012eb6b5 | ||
|
|
c79578e99f | ||
|
|
64626b8bc3 | ||
|
|
85c0b95a3c | ||
|
|
b48d9a6bac | ||
|
|
961fe70cb8 | ||
|
|
65267af512 | ||
|
|
ac387f208a | ||
|
|
80304d8804 | ||
|
|
cafb1a5a45 | ||
|
|
feef9b1b8d | ||
|
|
4aec27890c | ||
|
|
58ae4417df | ||
|
|
6287bfd9d9 | ||
|
|
5f139c0cb6 | ||
|
|
6cf257ac01 | ||
|
|
5cb5faa8a3 | ||
|
|
a28f2fd21d | ||
|
|
dbf12e1fa4 | ||
|
|
264629cfa5 | ||
|
|
53f49f3b07 | ||
|
|
a26016fc08 | ||
|
|
bd969e0bc3 | ||
|
|
3e96fe4a72 | ||
|
|
19299ad47f | ||
|
|
8902a3ca44 | ||
|
|
4015ff08a6 | ||
|
|
9bc50749ae | ||
|
|
34271605c3 | ||
|
|
8272a160d2 | ||
|
|
abf738ffee | ||
|
|
e439fb00b5 | ||
|
|
e1fa7440da | ||
|
|
24cff4d6ee | ||
|
|
0df5cd478b | ||
|
|
3a55b766c3 |
@@ -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
|
||||
|
||||
@@ -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
3
.gitignore
vendored
@@ -177,3 +177,6 @@ packages.config.md5sum
|
||||
**/.idea/**/*.iml
|
||||
**/.idea/**/contentModel.xml
|
||||
**/.idea/**/modules.xml
|
||||
# ignore node_modules symlink
|
||||
node_modules
|
||||
node_modules.nosync
|
||||
|
||||
38
CHANGELOG.md
38
CHANGELOG.md
@@ -2,6 +2,43 @@
|
||||
|
||||
## (unreleased)
|
||||
|
||||
### **New features**
|
||||
-  Tags support to NetImport (Lists) ([#3127](https://github.com/Radarr/Radarr/issues/3127)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Improved templates for h264 & h265 custom formats ([#3432](https://github.com/Radarr/Radarr/issues/3432)) [<a href="https://github.com/RhinoRhys">RhinoRhys</a>]
|
||||
-  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>]
|
||||
-  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>]
|
||||
-  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>]
|
||||
-  Added support for Gotify notifications ([#3474](https://github.com/Radarr/Radarr/issues/3474)) [<a href="https://github.com/stephanrenggli">stephanrenggli</a>]
|
||||
-  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>]
|
||||
-  Support Krypton Kodi Unique Ids ([#3388](https://github.com/Radarr/Radarr/issues/3388)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  Adjust Max Slider Value for Qualities ([#3393](https://github.com/Radarr/Radarr/issues/3393)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  README.md ([#3409](https://github.com/Radarr/Radarr/issues/3409)) [<a href="https://github.com/hotio">hotio</a>]
|
||||
-  Nzb Validation and Nzbget/SAB URLBase ([#3380](https://github.com/Radarr/Radarr/issues/3380)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  README.md. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  docker link in README. [<a href="https://github.com/hotio">hotio</a>]
|
||||
|
||||
### **Fixes**
|
||||
-  Solve ambiguous naming ([#3417](https://github.com/Radarr/Radarr/issues/3417)) [<a href="https://github.com/Viserius">Viserius</a>]
|
||||
-  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>]
|
||||
-  Edition Tags Not Showing in UI ([#3389](https://github.com/Radarr/Radarr/issues/3389)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  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>]
|
||||
-  MediaCovers Race condition which leads to fanart not being downloaded. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Cannot Add ITA or ITALIAN custom format ([#3385](https://github.com/Radarr/Radarr/issues/3385)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  OsInfo for real this time. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  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>]
|
||||
-  Forced Subs not parsed by SubtitleLanguageRegex ([#3384](https://github.com/Radarr/Radarr/issues/3384)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  OsInfo being renamed to PlatformInfo. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Word Boundary on Edition ([#3382](https://github.com/Radarr/Radarr/issues/3382)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  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>]
|
||||
-  Match MBluray releases ([#3358](https://github.com/Radarr/Radarr/issues/3358)) [<a href="https://github.com/Pieter Janssens">Pieter Janssens</a>]
|
||||
-  Mono bug causing memory leakage when http connections use gzip compression. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Build errors due to dotnet library. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Emby library update ([#3318](https://github.com/Radarr/Radarr/issues/3318)) [<a href="https://github.com/hatharry">hatharry</a>]
|
||||
-  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**
|
||||
-  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>]
|
||||
-  Support for forcedUP status ([#3277](https://github.com/Radarr/Radarr/issues/3277)) [<a href="https://github.com/Swizzy">Swizzy</a>]
|
||||
@@ -10,6 +47,7 @@
|
||||
-  Secure URLs for Links and Services ([#3219](https://github.com/Radarr/Radarr/issues/3219)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
|
||||
### **Fixes**
|
||||
-  Hopefully fixed sqlite errors when finding by title. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Another IDisposable leak when lazy loading properties. [<a href="https://github.com/Taloth Saldono">Taloth Saldono</a>]
|
||||
-  MediaCoverService tests and stupidly forgetting to open the database connection for logging. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  MediaCovers resizing potentially leaking memory when concurrently executing. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
|
||||
BIN
Logo/256.png
BIN
Logo/256.png
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 28 KiB |
11
README.md
11
README.md
@@ -22,13 +22,12 @@ See the [Roadmap blogpost](https://blog.radarr.video/development/update/2018/11/
|
||||
|
||||
## Downloads
|
||||
|
||||
[](https://github.com/Radarr/Radarr/releases)
|
||||
[](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
|
||||
Branch | develop (stable) | nightly (semi-unstable) |
|
||||
---|---|---
|
||||
Binary Releases | [](https://github.com/Radarr/Radarr/releases) | [](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
|
||||
Docker (linuxserver.io, x86_64, arm64, armhf) | [](https://store.docker.com/community/images/linuxserver/radarr) | [](https://store.docker.com/community/images/linuxserver/radarr)
|
||||
Docker (hotio, see [here](https://github.com/hotio/docker-radarr) for more information) | [](https://hub.docker.com/r/hotio/radarr) | [](https://hub.docker.com/r/hotio/radarr)
|
||||
|
||||
[](https://store.docker.com/community/images/linuxserver/radarr)
|
||||
[](https://store.docker.com/community/images/hotio/suitarr)
|
||||
[](https://store.docker.com/community/images/lsioarmhf/radarr)
|
||||
[](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
|
||||
|
||||
## Support
|
||||
|
||||
|
||||
4
build.sh
4
build.sh
@@ -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
102
package-lock.json
generated
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/NzbDrone.Core.Test/Files/Nzbs/NoFiles.nzb
Normal file
6
src/NzbDrone.Core.Test/Files/Nzbs/NoFiles.nzb
Normal 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>
|
||||
102
src/NzbDrone.Core.Test/Files/Nzbs/NotNzb.nzb
Normal file
102
src/NzbDrone.Core.Test/Files/Nzbs/NotNzb.nzb
Normal 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] - "Series.Title.s04e06.720p.hdtv.x264-killers.nfo" 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] - "Series.Title.s04e06.720p.hdtv.x264-killers.par2" 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] - "Series.Title.s04e06.720p.hdtv.x264-killers.r00" 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] - "sample-Series.Title.s04e06.720p.hdtv.x264-killers.vol31+04.par2" 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>
|
||||
105
src/NzbDrone.Core.Test/Files/Nzbs/ValidNzb.nzb
Normal file
105
src/NzbDrone.Core.Test/Files/Nzbs/ValidNzb.nzb
Normal 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] - "Series.Title.s04e06.720p.hdtv.x264-killers.nfo" 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] - "Series.Title.s04e06.720p.hdtv.x264-killers.par2" 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] - "Series.Title.s04e06.720p.hdtv.x264-killers.r00" 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] - "sample-Series.Title.s04e06.720p.hdtv.x264-killers.vol31+04.par2" 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>
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = '[]'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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."
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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."
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
24
src/NzbDrone.Core/Download/InvalidNzbException.cs
Normal file
24
src/NzbDrone.Core/Download/InvalidNzbException.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/NzbDrone.Core/Download/NzbValidationService.cs
Normal file
45
src/NzbDrone.Core/Download/NzbValidationService.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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\?.+$"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
63
src/NzbDrone.Core/Notifications/Gotify/Gotify.cs
Normal file
63
src/NzbDrone.Core/Notifications/Gotify/Gotify.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/NzbDrone.Core/Notifications/Gotify/GotifyPriority.cs
Normal file
10
src/NzbDrone.Core/Notifications/Gotify/GotifyPriority.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace NzbDrone.Core.Notifications.Gotify
|
||||
{
|
||||
public enum GotifyPriority
|
||||
{
|
||||
Min = 0,
|
||||
Low = 2,
|
||||
Normal = 5,
|
||||
High = 8
|
||||
}
|
||||
}
|
||||
26
src/NzbDrone.Core/Notifications/Gotify/GotifyService.cs
Normal file
26
src/NzbDrone.Core/Notifications/Gotify/GotifyService.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs
Normal file
40
src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Gotify
|
||||
{
|
||||
public class InvalidResponseException : Exception
|
||||
{
|
||||
public InvalidResponseException()
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidResponseException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 == "(")
|
||||
|
||||
@@ -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)|
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
18
src/ParsingLibrary/NzbDroneLogger.cs
Normal file
18
src/ParsingLibrary/NzbDroneLogger.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
95
src/ParsingLibrary/ParsingLibrary.csproj
Normal file
95
src/ParsingLibrary/ParsingLibrary.csproj
Normal 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>
|
||||
12
src/ParsingLibrary/PathExtensions.cs
Normal file
12
src/ParsingLibrary/PathExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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?';
|
||||
|
||||
|
||||
@@ -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' });
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -9,7 +9,7 @@ var view = Marionette.ItemView.extend({
|
||||
|
||||
slider : {
|
||||
min : 0,
|
||||
max : 200,
|
||||
max : 400,
|
||||
step : 0.1
|
||||
},
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -29,7 +29,6 @@ require.config({
|
||||
'messenger' : 'JsLibraries/messenger',
|
||||
'jquery' : 'JsLibraries/jquery',
|
||||
'typeahead' : 'JsLibraries/typeahead',
|
||||
'zero.clipboard' : 'JsLibraries/zero.clipboard',
|
||||
'libs' : 'JsLibraries/'
|
||||
},
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ require('jquery.knob');
|
||||
require('jquery.easypiechart');
|
||||
require('jquery.dotdotdot');
|
||||
require('typeahead');
|
||||
require('zero.clipboard');
|
||||
|
||||
/*Bootstrap*/
|
||||
require('bootstrap');
|
||||
|
||||
4
test.sh
4
test.sh
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user