mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-11 20:28:20 -04:00
Compare commits
83 Commits
v0.2.0.121
...
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 | ||
|
|
e7ad09cf62 | ||
|
|
420cbf6dd0 | ||
|
|
02eb30b8ee | ||
|
|
49b1f2a67d | ||
|
|
7c90667965 | ||
|
|
6d3cff85ae | ||
|
|
b9aba5f424 | ||
|
|
47b481e797 | ||
|
|
3ef224ed1d | ||
|
|
44b1252ecc | ||
|
|
44842a4e6b | ||
|
|
cd520b0341 | ||
|
|
fed4a0aebe | ||
|
|
ff894d5210 | ||
|
|
92b5822a39 | ||
|
|
cbdea30a6e | ||
|
|
969ef5c515 | ||
|
|
5b52115d68 | ||
|
|
899bd086ec | ||
|
|
d02d71c336 | ||
|
|
d4061bd13c | ||
|
|
c83995adc1 | ||
|
|
df18c34878 | ||
|
|
eb077b043e | ||
|
|
42015d5d95 | ||
|
|
09899fcf6c | ||
|
|
8e7b718209 | ||
|
|
d38562664d | ||
|
|
abf738ffee | ||
|
|
77950645af | ||
|
|
60a9be71bc | ||
|
|
49ee288dae | ||
|
|
443995cd93 | ||
|
|
1456200717 | ||
|
|
28155b09a0 | ||
|
|
9ba1d26f05 | ||
|
|
e439fb00b5 | ||
|
|
e1fa7440da | ||
|
|
e0e531c287 | ||
|
|
24cff4d6ee | ||
|
|
0df5cd478b | ||
|
|
3a55b766c3 |
@@ -1,13 +1,14 @@
|
||||
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
|
||||
ENV GOPATH=$HOME/work
|
||||
ENV PATH="${PATH}:/usr/local/go/bin:$GOPATH/bin"
|
||||
RUN go get github.com/aktau/github-release
|
||||
RUN npm install -g yarn
|
||||
@@ -2,7 +2,7 @@ version: 2
|
||||
|
||||
defaults: &defaults
|
||||
docker:
|
||||
- image: gallileo/radarr-cci-primary:5.8.7
|
||||
- image: gallileo/radarr-cci-primary:5.8.9
|
||||
environment:
|
||||
BUILD_VERSION: 0.2.0
|
||||
|
||||
@@ -62,6 +62,7 @@ jobs:
|
||||
- _tests
|
||||
- setup
|
||||
- .circleci
|
||||
- deploy.sh
|
||||
unit_tests:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -105,10 +106,10 @@ jobs:
|
||||
zip -r _packages/Radarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.windows.zip _packages/Radarr
|
||||
rm -rf _packages/Radarr
|
||||
cp -r _output_mono/ _packages/Radarr
|
||||
tar -zcvf _packages/Radarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.linux.tar.gz _packages/Radarr
|
||||
tar -zcvf _packages/Radarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.linux.tar.gz -C _packages Radarr
|
||||
rm -rf _packages/Radarr
|
||||
cp -r _output_osx/ _packages/Radarr
|
||||
tar -zcvf _packages/Radarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.osx.tar.gz _packages/Radarr
|
||||
tar -zcvf _packages/Radarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.osx.tar.gz -C _packages Radarr
|
||||
rm -rf _packages/Radarr
|
||||
cd _output_osx_app/
|
||||
zip -r ../_packages/Radarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.osx-app.zip *
|
||||
@@ -118,6 +119,9 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: _packages
|
||||
destination: artifacts
|
||||
#- run:
|
||||
# name: "Deploying"
|
||||
# command: chmod +x deploy.sh && ./deploy.sh
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
# Must be relative path from root
|
||||
|
||||
@@ -82,13 +82,13 @@ ignore_regexps = [
|
||||
## whenever you are tweaking this variable.
|
||||
##
|
||||
section_regexps = [
|
||||
('**New features**', [
|
||||
('**New features:**', [
|
||||
r'^[aA]dded?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
||||
r'^[uU]pdated?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
||||
r'^[cC]hanged?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
||||
r'^[nN]ew?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
|
||||
]),
|
||||
('**Fixes**', [
|
||||
('**Fixes:**', [
|
||||
r'^(?![mM]erge\s*)'
|
||||
]
|
||||
),
|
||||
@@ -151,7 +151,7 @@ subject_process = (strip |
|
||||
ReSub(r'^([cC]hang(ed?)?)(\s?:?\s)(.*)$', r'\4') |
|
||||
ReSub(r'^([fF]ix(ed?)?)(\s?:?\s)(.*)$', r'\4') |
|
||||
ReSub(r'^([uU]pdat(ed?)?)(\s?:?\s)(.*)$', r'\4') |
|
||||
ReSub(r'#(\d{3,4})', r'<a href="https://github.com/Radarr/Radarr/issues/\1">\1</a>') |
|
||||
ReSub(r'#(\d{3,4})', r'Issue #\1') |
|
||||
SetIfEmpty("No commit message.") | ucfirst | final_dot)
|
||||
|
||||
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -104,7 +104,7 @@ _TeamCity*
|
||||
# Radarr
|
||||
Backups/
|
||||
logs/
|
||||
MediaCover/
|
||||
#MediaCover/
|
||||
UpdateLogs/
|
||||
xdg/
|
||||
config.xml
|
||||
@@ -177,3 +177,6 @@ packages.config.md5sum
|
||||
**/.idea/**/*.iml
|
||||
**/.idea/**/contentModel.xml
|
||||
**/.idea/**/modules.xml
|
||||
# ignore node_modules symlink
|
||||
node_modules
|
||||
node_modules.nosync
|
||||
|
||||
78
CHANGELOG.md
78
CHANGELOG.md
@@ -3,6 +3,78 @@
|
||||
## (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>]
|
||||
-  rTorrent - Don't start download automatically ([#3222](https://github.com/Radarr/Radarr/issues/3222)) [<a href="https://github.com/lps-rocks">lps-rocks</a>]
|
||||
-  Remove Pre, postbot, xpost suffixes from release groups ([#3220](https://github.com/Radarr/Radarr/issues/3220)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  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>]
|
||||
-  Stream leakage inside CurlHttpDispatcher. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Apparently Microsoft thinks that you should cast to IDisposable first. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Invalid SQLite cache size. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Resource leakage inside HttpClient. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Typo that could probably lead to an infinite loop. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Resource leakage inside ManagedHttpDispatcher. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Leaking of objects when logging something to the database. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  DataMapper potentially leaking stuff when being disposed. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  DataMapper not being disposed, leading to resource leakage. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Memory leak due to unmanaged Bitmaps leaking. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Unable to parse movies from 1800s. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  OSX Packages not getting correct version info. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  npm start not working with node 10. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Hopefully fixed issue where a null downloadId or title would cause no downloads to be tracked. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Bump default version to prevent update running from source ([#3199](https://github.com/Radarr/Radarr/issues/3199)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
-  MediaInfo Unit Test Failing due to AudioAdditionalFeatures ([#3221](https://github.com/Radarr/Radarr/issues/3221)) [<a href="https://github.com/Qstick">Qstick</a>]
|
||||
|
||||
|
||||
## v0.2.0.1216 (2018-11-07)
|
||||
|
||||
### **New features**
|
||||
-  64bit mediainfo.dll to 32bit to resolve issue: https://github.com/Radarr/Radarr/issues/3138. [<a href="https://github.com/geogolem">geogolem</a>]
|
||||
-  Refactor MediaInfo tokens (fixes old tokens adds new stuff) ([#3058](https://github.com/Radarr/Radarr/issues/3058)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Don't hide custom formats behind advanced settings when editing quality. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Upped rate at which we scan the download client. Should reduce cpu and ram usage as well as decrease pressure on download clients. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Improve model and UI handling for lists. Should finally fix root folder errors. ([#3133](https://github.com/Radarr/Radarr/issues/3133)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Don't return unmapped folders on rootfolder API call. Massively improves loading time. ([#3116](https://github.com/Radarr/Radarr/issues/3116)) [<a href="https://github.com/Justin Kromlinger">Justin Kromlinger</a>]
|
||||
@@ -20,6 +92,12 @@
|
||||
-  "importing an episode" to "importing a movie file" ([#2829](https://github.com/Radarr/Radarr/issues/2829)) [<a href="https://github.com/Travis Boss">Travis Boss</a>]
|
||||
|
||||
### **Fixes**
|
||||
-  Fallback to 'VideoCodec' if 'VideoFormat' is unavailable ([#3142](https://github.com/Radarr/Radarr/issues/3142)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Read video 'BitRate_Nominal' if 'BitRate' is empty ([#3144](https://github.com/Radarr/Radarr/issues/3144)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  UpdateMovieQualityService Tests. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Ignore "special drives" from System » Disk Space ([#3050](https://github.com/Radarr/Radarr/issues/3050)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Tweak style of movie path template on "add movies" screen ([#3108](https://github.com/Radarr/Radarr/issues/3108)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Unable to update custom formats for releases with bad Source Titles. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
|
||||
-  Do not search movie if unmonitored ([#3131](https://github.com/Radarr/Radarr/issues/3131)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Quality badges not being shown on bulk import. ([#3121](https://github.com/Radarr/Radarr/issues/3121)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
|
||||
-  Trim filename from Kodi movie path before sending library scan request. ([#3097](https://github.com/Radarr/Radarr/issues/3097)) [<a href="https://github.com/Lawrence">Lawrence</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 |
20
README.md
20
README.md
@@ -6,6 +6,8 @@ Radarr is an __independent__ fork of [Sonarr](https://github.com/Sonarr/Sonarr)
|
||||
|
||||
The project was inspired by other Usenet/BitTorrent movie downloaders such as CouchPotato.
|
||||
|
||||
See the [Roadmap blogpost](https://blog.radarr.video/development/update/2018/11/11/roadmap-update.html) for an overview of planned features.
|
||||
|
||||
## Getting Started
|
||||
|
||||
[](https://github.com/Radarr/Radarr/wiki/Installation)
|
||||
@@ -20,13 +22,12 @@ The project was inspired by other Usenet/BitTorrent movie downloaders such as Co
|
||||
|
||||
## 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
|
||||
|
||||
@@ -93,12 +94,7 @@ Radarr is currently undergoing rapid development and pull requests are actively
|
||||
|
||||
### Planned Features
|
||||
|
||||
* Dynamically renaming folders with quality info, etc. (Currently working partially.) (\*)
|
||||
* Supporting custom folder structures, such as all movie files in one folder (\*)
|
||||
* Supporting multiple editions per movies (\*)
|
||||
* Supporting collections of movies, such as James Bond (\*)
|
||||
|
||||
**Note:** All features marked with (\*) are set to be in the first release of Radarr.
|
||||
See the [Roadmap blogpost](https://blog.radarr.video/development/update/2018/11/11/roadmap-update.html) for an overview of planned features.
|
||||
|
||||
#### [Feature Requests](http://feathub.com/Radarr/Radarr)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#addin nuget:?package=Cake.Npm
|
||||
#addin nuget:?package=SharpZipLib
|
||||
#addin nuget:?package=Cake.Compression
|
||||
#addin "Cake.FileHelpers"
|
||||
|
||||
// Build variables
|
||||
var outputFolder = "./_output";
|
||||
@@ -178,7 +179,7 @@ Task("PackageOsx").Does(() => {
|
||||
CopyFile("./osx/Radarr", outputFolderOsx + "/Radarr");
|
||||
});
|
||||
|
||||
Task("PackageOsxApp").Does(() => {
|
||||
Task("PackageOsxApp").Does((ctx) => {
|
||||
// Start osx app package
|
||||
if (DirectoryExists(outputFolderOsxApp)) {
|
||||
DeleteDirectory(outputFolderOsxApp, true);
|
||||
@@ -189,6 +190,9 @@ Task("PackageOsxApp").Does(() => {
|
||||
// Copy osx package files
|
||||
CopyDirectory("./osx/Radarr.app", outputFolderOsxApp + "/Radarr.app");
|
||||
CopyDirectory(outputFolderOsx, outputFolderOsxApp + "/Radarr.app/Contents/MacOS");
|
||||
|
||||
// Edit version of osx app
|
||||
ctx.ReplaceTextInFiles(outputFolderOsxApp + "/Radarr.app/Contents/Info.plist", "2.0", ctx.EnvironmentVariable("APPVEYOR_BUILD_VERSION") ?? "unknown");
|
||||
});
|
||||
|
||||
Task("PackageTests").Does(() => {
|
||||
|
||||
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
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{{#sections}}
|
||||
{{{label}}}
|
||||
{{#commits}}
|
||||
- {{{subject}}} [<a href="https://github.com/{{{author}}}">{{{author}}}</a>]
|
||||
- {{{subject}}} [{{{author}}}]
|
||||
{{/commits}}
|
||||
|
||||
{{/sections}}
|
||||
|
||||
0
debian/rules
vendored
Executable file → Normal file
0
debian/rules
vendored
Executable file → Normal file
7
deploy.sh
Normal file
7
deploy.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
if [ -z "$CIRCLE_PULL_REQUEST" ]; then
|
||||
echo "We are building a normal branch, deploying as such..."
|
||||
curl "http://pr.radarr.video:4466/deploy?url=https%3A%2F%2F${CIRCLE_BUILD_NUM}-77323220-gh.circle-artifacts.com%2F0%2Fartifacts%2FRadarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.linux.tar.gz&b=branch&name=${CIRCLE_BRANCH}"
|
||||
else
|
||||
echo "We are building a pr, deploying as such..."
|
||||
curl "http://pr.radarr.video:4466/deploy?url=https%3A%2F%2F${CIRCLE_BUILD_NUM}-77323220-gh.circle-artifacts.com%2F0%2Fartifacts%2FRadarr.${CIRCLE_BRANCH//\//-}.$BUILD_VERSION.$CIRCLE_BUILD_NUM.linux.tar.gz&b=pr&name=${CIRCLE_PR_NUMBER}"
|
||||
fi
|
||||
3950
package-lock.json
generated
3950
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,7 @@
|
||||
"tar.gz": "0.1.1",
|
||||
"url-search-params": "^0.6.1",
|
||||
"webpack": "1.12.0",
|
||||
"webpack-stream": "2.1.0"
|
||||
"webpack-stream": "2.1.0",
|
||||
"natives": "^1.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
4
src/.idea/.idea.NzbDrone/.idea/encodings.xml
generated
Normal file
4
src/.idea/.idea.NzbDrone/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
||||
6
src/.idea/.idea.NzbDrone/.idea/misc.xml
generated
Normal file
6
src/.idea/.idea.NzbDrone/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
|
||||
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("0.1.0.*")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
|
||||
@@ -941,21 +941,21 @@ namespace Marr.Data
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (Command.Transaction != null)
|
||||
if (_command != null)
|
||||
{
|
||||
Command.Transaction.Dispose();
|
||||
Command.Transaction = null;
|
||||
}
|
||||
if (_command.Transaction != null)
|
||||
{
|
||||
_command.Transaction.Dispose();
|
||||
_command.Transaction = null;
|
||||
}
|
||||
|
||||
if (Command.Connection != null)
|
||||
{
|
||||
Command.Connection.Dispose();
|
||||
Command.Connection = null;
|
||||
}
|
||||
if (_command.Connection != null)
|
||||
{
|
||||
_command.Connection.Dispose();
|
||||
_command.Connection = null;
|
||||
}
|
||||
|
||||
if (Command != null)
|
||||
{
|
||||
Command.Dispose();
|
||||
_command.Dispose();
|
||||
_command = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Data.Common;
|
||||
@@ -91,9 +91,11 @@ namespace Marr.Data.Mapping
|
||||
Type entType = ent.GetType();
|
||||
if (_repos.Relationships.ContainsKey(entType))
|
||||
{
|
||||
var provider = _db.ProviderFactory;
|
||||
var connectionString = _db.ConnectionString;
|
||||
Func<IDataMapper> dbCreate = () =>
|
||||
{
|
||||
var db = new DataMapper(_db.ProviderFactory, _db.ConnectionString);
|
||||
var db = new DataMapper(provider, connectionString);
|
||||
db.SqlMode = SqlModes.Text;
|
||||
return db;
|
||||
};
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,18 @@ using NzbDrone.Common.Http;
|
||||
|
||||
namespace NzbDrone.Common.Cloud
|
||||
{
|
||||
public interface ISonarrCloudRequestBuilder
|
||||
public interface IRadarrCloudRequestBuilder
|
||||
{
|
||||
IHttpRequestBuilderFactory Services { get; }
|
||||
IHttpRequestBuilderFactory SkyHookTvdb { get; }
|
||||
IHttpRequestBuilderFactory TMDB { get; }
|
||||
IHttpRequestBuilderFactory TMDBSingle { get; }
|
||||
}
|
||||
|
||||
public class SonarrCloudRequestBuilder : ISonarrCloudRequestBuilder
|
||||
public class RadarrCloudRequestBuilder : IRadarrCloudRequestBuilder
|
||||
{
|
||||
public SonarrCloudRequestBuilder()
|
||||
public RadarrCloudRequestBuilder()
|
||||
{
|
||||
Services = new HttpRequestBuilder("http://radarr.aeonlucid.com/v1/")
|
||||
.CreateFactory();
|
||||
|
||||
SkyHookTvdb = new HttpRequestBuilder("http://skyhook.sonarr.tv/v1/tvdb/{route}/{language}/")
|
||||
.SetSegment("language", "en")
|
||||
Services = new HttpRequestBuilder("https://radarr.aeonlucid.com/v1/")
|
||||
.CreateFactory();
|
||||
|
||||
TMDB = new HttpRequestBuilder("https://api.themoviedb.org/3/{route}/{id}{secondaryRoute}")
|
||||
@@ -31,7 +26,6 @@ namespace NzbDrone.Common.Cloud
|
||||
}
|
||||
|
||||
public IHttpRequestBuilderFactory Services { get; private set; }
|
||||
public IHttpRequestBuilderFactory SkyHookTvdb { get; private set; }
|
||||
public IHttpRequestBuilderFactory TMDB { get; private set; }
|
||||
public IHttpRequestBuilderFactory TMDBSingle { get; private set; }
|
||||
}
|
||||
@@ -123,27 +123,6 @@ namespace NzbDrone.Common.Disk
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsValidGDIPlusImage(string filename)
|
||||
{
|
||||
if (!CanUseGDIPlus())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var bmp = new Bitmap(filename))
|
||||
{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(ex, "Corrupted image found at: {0}.", filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FolderWritable(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace NzbDrone.Common.Disk
|
||||
bool FileExists(string path);
|
||||
bool FileExists(string path, StringComparison stringComparison);
|
||||
bool CanUseGDIPlus();
|
||||
bool IsValidGDIPlusImage(string path);
|
||||
bool FolderWritable(string path);
|
||||
string[] GetDirectories(string path);
|
||||
string[] GetFiles(string path, SearchOption searchOption);
|
||||
|
||||
@@ -66,95 +66,96 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
|
||||
lock (CurlGlobalHandle.Instance)
|
||||
{
|
||||
Stream responseStream = new MemoryStream();
|
||||
Stream headerStream = new MemoryStream();
|
||||
|
||||
using (var curlEasy = new CurlEasy())
|
||||
using (Stream responseStream = new MemoryStream())
|
||||
using (Stream headerStream = new MemoryStream())
|
||||
{
|
||||
curlEasy.AutoReferer = false;
|
||||
curlEasy.WriteFunction = (b, s, n, o) =>
|
||||
using (var curlEasy = new CurlEasy())
|
||||
{
|
||||
responseStream.Write(b, 0, s * n);
|
||||
return s * n;
|
||||
};
|
||||
curlEasy.HeaderFunction = (b, s, n, o) =>
|
||||
{
|
||||
headerStream.Write(b, 0, s * n);
|
||||
return s * n;
|
||||
};
|
||||
|
||||
AddProxy(curlEasy, request);
|
||||
|
||||
curlEasy.Url = request.Url.FullUri;
|
||||
|
||||
switch (request.Method)
|
||||
{
|
||||
case HttpMethod.GET:
|
||||
curlEasy.HttpGet = true;
|
||||
break;
|
||||
|
||||
case HttpMethod.POST:
|
||||
curlEasy.Post = true;
|
||||
break;
|
||||
|
||||
case HttpMethod.PUT:
|
||||
curlEasy.Put = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method));
|
||||
}
|
||||
curlEasy.FollowLocation = false;
|
||||
curlEasy.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; ;
|
||||
|
||||
if (request.RequestTimeout != TimeSpan.Zero)
|
||||
{
|
||||
curlEasy.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalSeconds);
|
||||
}
|
||||
|
||||
if (OsInfo.IsWindows)
|
||||
{
|
||||
curlEasy.CaInfo = _caBundleFilePath;
|
||||
}
|
||||
|
||||
if (cookies != null)
|
||||
{
|
||||
curlEasy.Cookie = cookies.GetCookieHeader((Uri)request.Url);
|
||||
}
|
||||
|
||||
if (request.ContentData != null)
|
||||
{
|
||||
curlEasy.PostFieldSize = request.ContentData.Length;
|
||||
curlEasy.SetOpt(CurlOption.CopyPostFields, new string(Array.ConvertAll(request.ContentData, v => (char)v)));
|
||||
}
|
||||
|
||||
// Yes, we have to keep a ref to the object to prevent corrupting the unmanaged state
|
||||
using (var httpRequestHeaders = SerializeHeaders(request))
|
||||
{
|
||||
curlEasy.HttpHeader = httpRequestHeaders;
|
||||
|
||||
var result = curlEasy.Perform();
|
||||
|
||||
if (result != CurlCode.Ok)
|
||||
curlEasy.AutoReferer = false;
|
||||
curlEasy.WriteFunction = (b, s, n, o) =>
|
||||
{
|
||||
switch (result)
|
||||
responseStream.Write(b, 0, s * n);
|
||||
return s * n;
|
||||
};
|
||||
curlEasy.HeaderFunction = (b, s, n, o) =>
|
||||
{
|
||||
headerStream.Write(b, 0, s * n);
|
||||
return s * n;
|
||||
};
|
||||
|
||||
AddProxy(curlEasy, request);
|
||||
|
||||
curlEasy.Url = request.Url.FullUri;
|
||||
|
||||
switch (request.Method)
|
||||
{
|
||||
case HttpMethod.GET:
|
||||
curlEasy.HttpGet = true;
|
||||
break;
|
||||
|
||||
case HttpMethod.POST:
|
||||
curlEasy.Post = true;
|
||||
break;
|
||||
|
||||
case HttpMethod.PUT:
|
||||
curlEasy.Put = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(string.Format("HttpCurl method {0} not supported", request.Method));
|
||||
}
|
||||
curlEasy.FollowLocation = false;
|
||||
curlEasy.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent; ;
|
||||
|
||||
if (request.RequestTimeout != TimeSpan.Zero)
|
||||
{
|
||||
curlEasy.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalSeconds);
|
||||
}
|
||||
|
||||
if (OsInfo.IsWindows)
|
||||
{
|
||||
curlEasy.CaInfo = _caBundleFilePath;
|
||||
}
|
||||
|
||||
if (cookies != null)
|
||||
{
|
||||
curlEasy.Cookie = cookies.GetCookieHeader((Uri)request.Url);
|
||||
}
|
||||
|
||||
if (request.ContentData != null)
|
||||
{
|
||||
curlEasy.PostFieldSize = request.ContentData.Length;
|
||||
curlEasy.SetOpt(CurlOption.CopyPostFields, new string(Array.ConvertAll(request.ContentData, v => (char)v)));
|
||||
}
|
||||
|
||||
// Yes, we have to keep a ref to the object to prevent corrupting the unmanaged state
|
||||
using (var httpRequestHeaders = SerializeHeaders(request))
|
||||
{
|
||||
curlEasy.HttpHeader = httpRequestHeaders;
|
||||
|
||||
var result = curlEasy.Perform();
|
||||
|
||||
if (result != CurlCode.Ok)
|
||||
{
|
||||
case CurlCode.SslCaCert:
|
||||
case (CurlCode)77:
|
||||
throw new WebException(string.Format("Curl Error {0} for Url {1}, issues with your operating system SSL Root Certificate Bundle (ca-bundle).", result, curlEasy.Url));
|
||||
default:
|
||||
throw new WebException(string.Format("Curl Error {0} for Url {1}", result, curlEasy.Url));
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case CurlCode.SslCaCert:
|
||||
case (CurlCode)77:
|
||||
throw new WebException(string.Format("Curl Error {0} for Url {1}, issues with your operating system SSL Root Certificate Bundle (ca-bundle).", result, curlEasy.Url));
|
||||
default:
|
||||
throw new WebException(string.Format("Curl Error {0} for Url {1}", result, curlEasy.Url));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var webHeaderCollection = ProcessHeaderStream(request, cookies, headerStream);
|
||||
var responseData = ProcessResponseStream(request, responseStream, webHeaderCollection);
|
||||
|
||||
var httpHeader = new HttpHeader(webHeaderCollection);
|
||||
|
||||
return new HttpResponse(request, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode);
|
||||
}
|
||||
|
||||
var webHeaderCollection = ProcessHeaderStream(request, cookies, headerStream);
|
||||
var responseData = ProcessResponseStream(request, responseStream, webHeaderCollection);
|
||||
|
||||
var httpHeader = new HttpHeader(webHeaderCollection);
|
||||
|
||||
return new HttpResponse(request, httpHeader, responseData, (HttpStatusCode)curlEasy.ResponseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,6 +260,7 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
|
||||
private byte[] ProcessResponseStream(HttpRequest request, Stream responseStream, WebHeaderCollection webHeaderCollection)
|
||||
{
|
||||
byte[] bytes = null;
|
||||
responseStream.Position = 0;
|
||||
|
||||
if (responseStream.Length != 0)
|
||||
@@ -268,21 +270,27 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
{
|
||||
if (encoding.IndexOf("gzip") != -1)
|
||||
{
|
||||
responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
|
||||
using (var zipStream = new GZipStream(responseStream, CompressionMode.Decompress))
|
||||
{
|
||||
bytes = zipStream.ToBytes();
|
||||
}
|
||||
|
||||
webHeaderCollection.Remove("Content-Encoding");
|
||||
}
|
||||
else if (encoding.IndexOf("deflate") != -1)
|
||||
{
|
||||
responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);
|
||||
using (var deflateStream = new DeflateStream(responseStream, CompressionMode.Decompress))
|
||||
{
|
||||
bytes = deflateStream.ToBytes();
|
||||
}
|
||||
|
||||
webHeaderCollection.Remove("Content-Encoding");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return responseStream.ToBytes();
|
||||
|
||||
if (bytes == null) bytes = responseStream.ToBytes();
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
@@ -20,72 +22,106 @@ namespace NzbDrone.Common.Http.Dispatchers
|
||||
|
||||
public HttpResponse GetResponse(HttpRequest request, CookieContainer cookies)
|
||||
{
|
||||
var 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;
|
||||
|
||||
webRequest.Method = request.Method.ToString();
|
||||
webRequest.UserAgent = request.UseSimplifiedUserAgent ? UserAgentBuilder.UserAgentSimplified : UserAgentBuilder.UserAgent;
|
||||
webRequest.KeepAlive = request.ConnectionKeepAlive;
|
||||
webRequest.AllowAutoRedirect = false;
|
||||
webRequest.CookieContainer = cookies;
|
||||
|
||||
if (request.RequestTimeout != TimeSpan.Zero)
|
||||
{
|
||||
webRequest.Timeout = (int)Math.Ceiling(request.RequestTimeout.TotalMilliseconds);
|
||||
}
|
||||
|
||||
AddProxy(webRequest, request);
|
||||
|
||||
if (request.Headers != null)
|
||||
{
|
||||
AddRequestHeaders(webRequest, request.Headers);
|
||||
}
|
||||
|
||||
if (request.ContentData != null)
|
||||
{
|
||||
webRequest.ContentLength = request.ContentData.Length;
|
||||
using (var writeStream = webRequest.GetRequestStream())
|
||||
{
|
||||
writeStream.Write(request.ContentData, 0, request.ContentData.Length);
|
||||
}
|
||||
}
|
||||
|
||||
HttpWebResponse httpWebResponse;
|
||||
|
||||
HttpWebResponse httpWebResponse = null;
|
||||
HttpWebRequest webRequest = null;
|
||||
try
|
||||
{
|
||||
httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
|
||||
webRequest = (HttpWebRequest) WebRequest.Create((Uri) request.Url);
|
||||
|
||||
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
|
||||
: UserAgentBuilder.UserAgent;
|
||||
webRequest.KeepAlive = request.ConnectionKeepAlive;
|
||||
webRequest.AllowAutoRedirect = false;
|
||||
webRequest.CookieContainer = cookies;
|
||||
|
||||
if (request.RequestTimeout != TimeSpan.Zero)
|
||||
{
|
||||
webRequest.Timeout = (int) Math.Ceiling(request.RequestTimeout.TotalMilliseconds);
|
||||
}
|
||||
|
||||
AddProxy(webRequest, request);
|
||||
|
||||
if (request.Headers != null)
|
||||
{
|
||||
AddRequestHeaders(webRequest, request.Headers);
|
||||
}
|
||||
|
||||
if (request.ContentData != null)
|
||||
{
|
||||
webRequest.ContentLength = request.ContentData.Length;
|
||||
using (var writeStream = webRequest.GetRequestStream())
|
||||
{
|
||||
writeStream.Write(request.ContentData, 0, request.ContentData.Length);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
httpWebResponse = (HttpWebResponse) webRequest.GetResponse();
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
if (e.Status == WebExceptionStatus.SecureChannelFailure && OsInfo.IsWindows)
|
||||
{
|
||||
SecurityProtocolPolicy.DisableTls12();
|
||||
}
|
||||
|
||||
httpWebResponse = (HttpWebResponse) e.Response;
|
||||
|
||||
if (httpWebResponse == null)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = null;
|
||||
|
||||
using (var responseStream = httpWebResponse.GetResponseStream())
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new HttpResponse(request, new HttpHeader(httpWebResponse.Headers), data,
|
||||
httpWebResponse.StatusCode);
|
||||
}
|
||||
catch (WebException e)
|
||||
finally
|
||||
{
|
||||
if (e.Status == WebExceptionStatus.SecureChannelFailure && OsInfo.IsWindows)
|
||||
{
|
||||
SecurityProtocolPolicy.DisableTls12();
|
||||
}
|
||||
|
||||
httpWebResponse = (HttpWebResponse)e.Response;
|
||||
|
||||
if (httpWebResponse == null)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
webRequest = null;
|
||||
(httpWebResponse as IDisposable)?.Dispose();
|
||||
httpWebResponse = null;
|
||||
}
|
||||
|
||||
byte[] data = null;
|
||||
|
||||
using (var responseStream = httpWebResponse.GetResponseStream())
|
||||
{
|
||||
if (responseStream != null)
|
||||
{
|
||||
data = responseStream.ToBytes();
|
||||
}
|
||||
}
|
||||
|
||||
return new HttpResponse(request, new HttpHeader(httpWebResponse.Headers), data, httpWebResponse.StatusCode);
|
||||
}
|
||||
|
||||
protected virtual void AddProxy(HttpWebRequest webRequest, HttpRequest request)
|
||||
|
||||
@@ -226,11 +226,13 @@ namespace NzbDrone.Common.Http
|
||||
_logger.Debug("Downloading [{0}] to [{1}]", url, fileName);
|
||||
|
||||
var stopWatch = Stopwatch.StartNew();
|
||||
var webClient = new GZipWebClient();
|
||||
webClient.Headers.Add(HttpRequestHeader.UserAgent, UserAgentBuilder.UserAgent);
|
||||
webClient.DownloadFile(url, fileName);
|
||||
stopWatch.Stop();
|
||||
_logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds);
|
||||
using (var webClient = new GZipWebClient())
|
||||
{
|
||||
webClient.Headers.Add(HttpRequestHeader.UserAgent, UserAgentBuilder.UserAgent);
|
||||
webClient.DownloadFile(url, fileName);
|
||||
stopWatch.Stop();
|
||||
_logger.Debug("Downloading Completed. took {0:0}s", stopWatch.Elapsed.Seconds);
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace NzbDrone.Common.Instrumentation
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(exception.StackTrace);
|
||||
|
||||
Console.WriteLine("EPIC FAIL: {0}", exception);
|
||||
Logger.Fatal(exception, "EPIC FAIL: " + exception.Message);
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
<Compile Include="Cache\CachedDictionary.cs" />
|
||||
<Compile Include="Cache\ICached.cs" />
|
||||
<Compile Include="Cache\ICachedDictionary.cs" />
|
||||
<Compile Include="Cloud\SonarrCloudRequestBuilder.cs" />
|
||||
<Compile Include="Cloud\RadarrCloudRequestBuilder.cs" />
|
||||
<Compile Include="Composition\Container.cs" />
|
||||
<Compile Include="Composition\ContainerBuilderBase.cs" />
|
||||
<Compile Include="Composition\IContainer.cs" />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("radarr.tv")]
|
||||
[assembly: AssemblyProduct("NzbDrone")]
|
||||
[assembly: AssemblyVersion("0.1.0.*")]
|
||||
[assembly: AssemblyCompany("radarr.video")]
|
||||
[assembly: AssemblyProduct("Radarr")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyCopyright("GNU General Public v3")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,11 +54,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
|
||||
protected void GivenSuccessfulDownload()
|
||||
{
|
||||
Mocker.GetMock<IRTorrentProxy>()
|
||||
.Setup(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
|
||||
.Setup(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<RTorrentSettings>()))
|
||||
.Callback(PrepareClientToReturnCompletedItem);
|
||||
|
||||
Mocker.GetMock<IRTorrentProxy>()
|
||||
.Setup(s => s.AddTorrentFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
|
||||
.Setup(s => s.AddTorrentFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<RTorrentSettings>()))
|
||||
.Callback(PrepareClientToReturnCompletedItem);
|
||||
|
||||
|
||||
@@ -123,4 +123,4 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
|
||||
id.Should().NotBeNullOrEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Framework
|
||||
Mocker.SetConstant<CurlHttpDispatcher>(new CurlHttpDispatcher(Mocker.Resolve<IHttpProxySettingsProvider>(), Mocker.Resolve<NLog.Logger>()));
|
||||
Mocker.SetConstant<IHttpProvider>(new HttpProvider(TestLogger));
|
||||
Mocker.SetConstant<IHttpClient>(new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve<CacheManager>(), Mocker.Resolve<RateLimitService>(), Mocker.Resolve<FallbackHttpDispatcher>(), TestLogger));
|
||||
Mocker.SetConstant<ISonarrCloudRequestBuilder>(new SonarrCloudRequestBuilder());
|
||||
Mocker.SetConstant<IRadarrCloudRequestBuilder>(new RadarrCloudRequestBuilder());
|
||||
}
|
||||
|
||||
//Used for tests that rely on parsing working correctly.
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -37,15 +37,6 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
|
||||
}
|
||||
|
||||
private void GivenImageFileCorrupt(bool corrupt)
|
||||
{
|
||||
GivenFileExistsOnDisk();
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.IsValidGDIPlusImage(It.IsAny<string>()))
|
||||
.Returns(!corrupt);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_file_not_exists()
|
||||
{
|
||||
@@ -61,21 +52,11 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_file_exists_and_same_size_and_corrupt()
|
||||
{
|
||||
GivenExistingFileSize(100);
|
||||
GivenImageFileCorrupt(true);
|
||||
_httpResponse.Headers.ContentLength = 100;
|
||||
Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeFalse();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_file_exists_and_same_size_and_not_corrupt()
|
||||
{
|
||||
GivenExistingFileSize(100);
|
||||
GivenImageFileCorrupt(false);
|
||||
_httpResponse.Headers.ContentLength = 100;
|
||||
Subject.AlreadyExists("http://url", "c:\\file.exe").Should().BeTrue();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Movies.Events;
|
||||
@@ -28,6 +29,18 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
.With(v => v.Id = 2)
|
||||
.With(v => v.Images = new List<MediaCover.MediaCover> { new MediaCover.MediaCover(MediaCoverTypes.Poster, "") })
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IMovieService>().Setup(m => m.GetMovie(It.Is<int>(id => id == _movie.Id))).Returns(_movie);
|
||||
}
|
||||
|
||||
private void ExecuteAndVerifyCommand(Movie movie)
|
||||
{
|
||||
Subject.HandleAsync(new MovieUpdatedEvent(movie));
|
||||
|
||||
Mocker.GetMock<IManageCommandQueue>()
|
||||
.Verify(v => v.Push(It.Is<EnsureMediaCoversCommand>(c => c.MovieId == movie.Id), It.IsAny<CommandPriority>(), It.IsAny<CommandTrigger>()), Times.Once());
|
||||
|
||||
Subject.Execute(new EnsureMediaCoversCommand(movie.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -76,7 +89,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
.Setup(v => v.FileExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
Subject.HandleAsync(new MovieUpdatedEvent(_movie));
|
||||
ExecuteAndVerifyCommand(_movie);
|
||||
|
||||
Mocker.GetMock<IImageResizer>()
|
||||
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(2));
|
||||
@@ -93,7 +106,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
.Setup(v => v.FileExists(It.IsAny<string>()))
|
||||
.Returns(false);
|
||||
|
||||
Subject.HandleAsync(new MovieUpdatedEvent(_movie));
|
||||
ExecuteAndVerifyCommand(_movie);
|
||||
|
||||
Mocker.GetMock<IImageResizer>()
|
||||
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(2));
|
||||
@@ -114,7 +127,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
.Setup(v => v.GetFileSize(It.IsAny<string>()))
|
||||
.Returns(1000);
|
||||
|
||||
Subject.HandleAsync(new MovieUpdatedEvent(_movie));
|
||||
ExecuteAndVerifyCommand(_movie);
|
||||
|
||||
Mocker.GetMock<IImageResizer>()
|
||||
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Never());
|
||||
@@ -135,7 +148,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
.Setup(v => v.GetFileSize(It.IsAny<string>()))
|
||||
.Returns(0);
|
||||
|
||||
Subject.HandleAsync(new MovieUpdatedEvent(_movie));
|
||||
ExecuteAndVerifyCommand(_movie);
|
||||
|
||||
Mocker.GetMock<IImageResizer>()
|
||||
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(2));
|
||||
@@ -156,7 +169,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
|
||||
.Setup(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()))
|
||||
.Throws<ApplicationException>();
|
||||
|
||||
Subject.HandleAsync(new MovieUpdatedEvent(_movie));
|
||||
ExecuteAndVerifyCommand(_movie);
|
||||
|
||||
Mocker.GetMock<IImageResizer>()
|
||||
.Verify(v => v.Resize(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>()), Times.Exactly(2));
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||
info.AudioBitrate.Should().Be(128000);
|
||||
info.AudioChannels.Should().Be(2);
|
||||
info.AudioLanguages.Should().Be("English");
|
||||
info.AudioAdditionalFeatures.Should().Be("");
|
||||
info.AudioAdditionalFeatures.Should().Be("LC");
|
||||
info.Height.Should().Be(320);
|
||||
info.RunTime.Seconds.Should().Be(10);
|
||||
info.ScanType.Should().Be("Progressive");
|
||||
@@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||
info.AudioBitrate.Should().Be(128000);
|
||||
info.AudioChannels.Should().Be(2);
|
||||
info.AudioLanguages.Should().Be("English");
|
||||
info.AudioAdditionalFeatures.Should().Be("");
|
||||
info.AudioAdditionalFeatures.Should().Be("LC");
|
||||
info.Height.Should().Be(320);
|
||||
info.RunTime.Seconds.Should().Be(10);
|
||||
info.ScanType.Should().Be("Progressive");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -43,7 +43,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||
[TestCase("To.Live.and.Die.in.L.A.1985.1080p.BluRay", "To Live and Die in L.A.")]
|
||||
[TestCase("A.I.Artificial.Intelligence.(2001)", "A.I. Artificial Intelligence")]
|
||||
[TestCase("A.Movie.Name.(1998)", "A Movie Name")]
|
||||
[TestCase("Thor: The Dark World 2013", "Thor The Dark World")]
|
||||
[TestCase("www.Torrenting.com - Revenge.2008.720p.X264-DIMENSION", "Revenge")]
|
||||
[TestCase("Thor: The Dark World 2013", "Thor The Dark World")]
|
||||
[TestCase("Resident.Evil.The.Final.Chapter.2016", "Resident Evil The Final Chapter")]
|
||||
[TestCase("Der.Soldat.James.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", "Der Soldat James")]
|
||||
[TestCase("Passengers.German.DL.AC3.Dubbed..BluRay.x264-PsO", "Passengers")]
|
||||
@@ -52,7 +53,10 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||
[TestCase("Mission Impossible: Rogue Nation (2015)<29>[XviD - Ita Ac3 - SoftSub Ita]azione, spionaggio, thriller *Prima Visione* Team mulnic Tom Cruise", "Mission Impossible Rogue Nation")]
|
||||
[TestCase("Scary.Movie.2000.FRENCH..BluRay.-AiRLiNE", "Scary Movie")]
|
||||
[TestCase("My Movie 1999 German Bluray", "My Movie")]
|
||||
public void should_parse_movie_title(string postTitle, string title)
|
||||
[TestCase("Leaving Jeruselem by Railway (1897) [DVD].mp4", "Leaving Jeruselem by Railway")]
|
||||
[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);
|
||||
}
|
||||
@@ -66,6 +70,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||
[TestCase("1941.1979.EXTENDED.720p.BluRay.X264-AMIABLE", 1979)]
|
||||
[TestCase("Valana la Legende FRENCH BluRay 720p 2016 kjhlj", 2016)]
|
||||
[TestCase("Der.Soldat.James.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", 1998)]
|
||||
[TestCase("Leaving Jeruselem by Railway (1897) [DVD].mp4", 1897)]
|
||||
public void should_parse_movie_year(string postTitle, int year)
|
||||
{
|
||||
Parser.Parser.ParseMovieTitle(postTitle, false).Year.Should().Be(year);
|
||||
@@ -108,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);
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||
[TestCase("[ www.Torrenting.com ] - Revenge.S03E14.720p.HDTV.X264-DIMENSION", "DIMENSION")]
|
||||
[TestCase("Seed S02E09 HDTV x264-2HD [eztv]-[rarbg.com]", "2HD")]
|
||||
[TestCase("7s-atlantis-s02e01-720p.mkv", null)]
|
||||
[TestCase("The.Middle.720p.HEVC.x265-MeGusta-Pre", "MeGusta")]
|
||||
[TestCase("Haunted.Hayride.2018.720p.WEBRip.DDP5.1.x264-NTb-postbot", "NTb")]
|
||||
[TestCase("Haunted.Hayride.2018.720p.WEBRip.DDP5.1.x264-NTb-xpost", "NTb")]
|
||||
//[TestCase("", "")]
|
||||
public void should_parse_release_group(string title, string expected)
|
||||
{
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace NzbDrone.Core.Authentication
|
||||
|
||||
public User FindUser(string username)
|
||||
{
|
||||
return Query.Where(u => u.Username == username).SingleOrDefault();
|
||||
return Query(q => q.Where(u => u.Username == username).SingleOrDefault());
|
||||
}
|
||||
|
||||
public User FindUser(Guid identifier)
|
||||
{
|
||||
return Query.Where(u => u.Identifier == identifier).SingleOrDefault();
|
||||
return Query(q => q.Where(u => u.Identifier == identifier).SingleOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,11 @@ namespace NzbDrone.Core.Backup
|
||||
|
||||
public void BackupDatabase(IDatabase database, string targetDirectory)
|
||||
{
|
||||
var sourceConnectionString = database.GetDataMapper().ConnectionString;
|
||||
var sourceConnectionString = "";
|
||||
using (var db = database.GetDataMapper())
|
||||
{
|
||||
sourceConnectionString = db.ConnectionString;
|
||||
}
|
||||
var backupConnectionStringBuilder = new SQLiteConnectionStringBuilder(sourceConnectionString);
|
||||
|
||||
backupConnectionStringBuilder.DataSource = Path.Combine(targetDirectory, Path.GetFileName(backupConnectionStringBuilder.DataSource));
|
||||
|
||||
@@ -22,19 +22,19 @@ namespace NzbDrone.Core.Blacklisting
|
||||
|
||||
public List<Blacklist> BlacklistedByTitle(int movieId, string sourceTitle)
|
||||
{
|
||||
return Query.Where(e => e.MovieId == movieId)
|
||||
.AndWhere(e => e.SourceTitle.Contains(sourceTitle));
|
||||
return Query(q => q.Where(e => e.MovieId == movieId)
|
||||
.AndWhere(e => e.SourceTitle.Contains(sourceTitle)).ToList());
|
||||
}
|
||||
|
||||
public List<Blacklist> BlacklistedByTorrentInfoHash(int movieId, string torrentInfoHash)
|
||||
{
|
||||
return Query.Where(e => e.MovieId == movieId)
|
||||
.AndWhere(e => e.TorrentInfoHash.Contains(torrentInfoHash));
|
||||
return Query(q => q.Where(e => e.MovieId == movieId)
|
||||
.AndWhere(e => e.TorrentInfoHash.Contains(torrentInfoHash)).ToList());
|
||||
}
|
||||
|
||||
public List<Blacklist> BlacklistedByMovie(int movieId)
|
||||
{
|
||||
return Query.Where(b => b.MovieId == movieId);
|
||||
return Query(q => q.Where(b => b.MovieId == movieId).ToList());
|
||||
}
|
||||
|
||||
protected override SortBuilder<Blacklist> GetPagedQuery(QueryBuilder<Blacklist> query, PagingSpec<Blacklist> pagingSpec)
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Configuration
|
||||
|
||||
public Config Get(string key)
|
||||
{
|
||||
return Query.Where(c => c.Key == key).SingleOrDefault();
|
||||
return Query(q => q.Where(c => c.Key == key).SingleOrDefault());
|
||||
}
|
||||
|
||||
public Config Upsert(string key, string value)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -42,7 +42,10 @@ namespace NzbDrone.Core.Datastore
|
||||
private readonly IDatabase _database;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
|
||||
protected IDataMapper DataMapper => _database.GetDataMapper();
|
||||
protected IDataMapper DataMapper()
|
||||
{
|
||||
return _database.GetDataMapper();
|
||||
}
|
||||
|
||||
public BasicRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||
{
|
||||
@@ -50,26 +53,40 @@ namespace NzbDrone.Core.Datastore
|
||||
_eventAggregator = eventAggregator;
|
||||
}
|
||||
|
||||
protected QueryBuilder<TModel> Query => AddJoinQueries(DataMapper.Query<TModel>());
|
||||
|
||||
protected T Query<T>(Func<QueryBuilder<TModel>, T> finalizeQuery)
|
||||
{
|
||||
using (var mapper = DataMapper())
|
||||
{
|
||||
var query = AddJoinQueries(mapper.Query<TModel>());
|
||||
return finalizeQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
protected void Delete(Expression<Func<TModel, bool>> filter)
|
||||
{
|
||||
DataMapper.Delete(filter);
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
db.Delete(filter);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TModel> All()
|
||||
{
|
||||
return Query.ToList();
|
||||
return Query((q => q.ToList()));
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
return DataMapper.Query<TModel>().GetRowCount();
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
return db.Query<TModel>().GetRowCount();
|
||||
}
|
||||
}
|
||||
|
||||
public TModel Get(int id)
|
||||
{
|
||||
var model = Query.Where(c => c.Id == id).SingleOrDefault();
|
||||
TModel model = Query(q => q.Where(c => c.Id == id).SingleOrDefault());
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
@@ -83,7 +100,7 @@ namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
var idList = ids.ToList();
|
||||
var query = string.Format("Id IN ({0})", string.Join(",", idList));
|
||||
var result = Query.Where(m => m.Id.In(idList)).ToList();
|
||||
var result = Query(q => q.Where(m => m.Id.In(idList)).ToList());
|
||||
//var result = Query.Where(query).ToList();
|
||||
|
||||
if (result.Count != idList.Count())
|
||||
@@ -111,7 +128,10 @@ namespace NzbDrone.Core.Datastore
|
||||
throw new InvalidOperationException("Can't insert model with existing ID " + model.Id);
|
||||
}
|
||||
|
||||
DataMapper.Insert(model);
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
db.Insert(model);
|
||||
}
|
||||
|
||||
ModelCreated(model);
|
||||
|
||||
@@ -125,7 +145,10 @@ namespace NzbDrone.Core.Datastore
|
||||
throw new InvalidOperationException("Can't update model with ID 0");
|
||||
}
|
||||
|
||||
DataMapper.Update(model, c => c.Id == model.Id);
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
db.Update(model, c => c.Id == model.Id);
|
||||
}
|
||||
|
||||
ModelUpdated(model);
|
||||
|
||||
@@ -139,7 +162,7 @@ namespace NzbDrone.Core.Datastore
|
||||
|
||||
public void InsertMany(IList<TModel> models)
|
||||
{
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper))
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper()))
|
||||
{
|
||||
unitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
|
||||
@@ -154,7 +177,7 @@ namespace NzbDrone.Core.Datastore
|
||||
|
||||
public void UpdateMany(IList<TModel> models)
|
||||
{
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper))
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper()))
|
||||
{
|
||||
unitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
|
||||
@@ -192,12 +215,15 @@ namespace NzbDrone.Core.Datastore
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
DataMapper.Delete<TModel>(c => c.Id == id);
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
db.Delete<TModel>(c => c.Id == id);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMany(IEnumerable<int> ids)
|
||||
{
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper))
|
||||
using (var unitOfWork = new UnitOfWork(() => DataMapper()))
|
||||
{
|
||||
unitOfWork.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
|
||||
@@ -214,7 +240,10 @@ namespace NzbDrone.Core.Datastore
|
||||
|
||||
public void Purge(bool vacuum = false)
|
||||
{
|
||||
DataMapper.Delete<TModel>(c => c.Id > -1);
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
db.Delete<TModel>(c => c.Id > -1);
|
||||
}
|
||||
if (vacuum)
|
||||
{
|
||||
Vacuum();
|
||||
@@ -238,20 +267,23 @@ namespace NzbDrone.Core.Datastore
|
||||
throw new InvalidOperationException("Attempted to updated model without ID");
|
||||
}
|
||||
|
||||
DataMapper.Update<TModel>()
|
||||
.Where(c => c.Id == model.Id)
|
||||
.ColumnsIncluding(properties)
|
||||
.Entity(model)
|
||||
.Execute();
|
||||
using (var db = DataMapper())
|
||||
{
|
||||
db.Update<TModel>()
|
||||
.Where(c => c.Id == model.Id)
|
||||
.ColumnsIncluding(properties)
|
||||
.Entity(model)
|
||||
.Execute();
|
||||
}
|
||||
|
||||
ModelUpdated(model);
|
||||
}
|
||||
|
||||
public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
pagingSpec.Records = GetPagedQuery(Query, pagingSpec).Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize).ToList();
|
||||
pagingSpec.TotalRecords = GetPagedQuery(Query, pagingSpec).GetRowCount();
|
||||
pagingSpec.Records = Query(q => GetPagedQuery(q, pagingSpec).Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize).ToList());
|
||||
pagingSpec.TotalRecords = Query(q => GetPagedQuery(q, pagingSpec).GetRowCount());
|
||||
|
||||
return pagingSpec;
|
||||
}
|
||||
@@ -285,7 +317,7 @@ namespace NzbDrone.Core.Datastore
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual QueryBuilder<TModel> AddJoinQueries(QueryBuilder<TModel> baseQuery)
|
||||
protected virtual QueryBuilder<TActual> AddJoinQueries<TActual>(QueryBuilder<TActual> baseQuery)
|
||||
{
|
||||
return baseQuery;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace NzbDrone.Core.Datastore
|
||||
var connectionBuilder = new SQLiteConnectionStringBuilder();
|
||||
|
||||
connectionBuilder.DataSource = dbPath;
|
||||
connectionBuilder.CacheSize = (int)-10.Megabytes();
|
||||
connectionBuilder.CacheSize = (int)-20000;
|
||||
connectionBuilder.DateTimeKind = DateTimeKind.Utc;
|
||||
connectionBuilder.JournalMode = OsInfo.IsOsx ? SQLiteJournalModeEnum.Truncate : SQLiteJournalModeEnum.Wal;
|
||||
connectionBuilder.Pooling = true;
|
||||
|
||||
@@ -34,8 +34,11 @@ namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
get
|
||||
{
|
||||
var version = _datamapperFactory().ExecuteScalar("SELECT sqlite_version()").ToString();
|
||||
return new Version(version);
|
||||
using (var db = _datamapperFactory())
|
||||
{
|
||||
var version = db.ExecuteScalar("SELECT sqlite_version()").ToString();
|
||||
return new Version(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +47,10 @@ namespace NzbDrone.Core.Datastore
|
||||
try
|
||||
{
|
||||
_logger.Info("Vacuuming {0} database", _databaseName);
|
||||
_datamapperFactory().ExecuteNonQuery("Vacuum;");
|
||||
using (var db = _datamapperFactory())
|
||||
{
|
||||
db.ExecuteNonQuery("Vacuum;");
|
||||
}
|
||||
_logger.Info("{0} database compressed", _databaseName);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -154,6 +154,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
case "stalledUP": // torrent is being seeded, but no connection were made
|
||||
case "queuedUP": // queuing is enabled and torrent is queued for upload
|
||||
case "checkingUP": // torrent has finished downloading and is being checked
|
||||
case "forcedUP": // torrent is beeing seeded by force
|
||||
item.Status = DownloadItemStatus.Completed;
|
||||
item.RemainingTime = TimeSpan.Zero; // qBittorrent sends eta=8640000 for completed torrents
|
||||
break;
|
||||
@@ -164,7 +165,12 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
||||
break;
|
||||
|
||||
case "downloading": // torrent is being downloaded and data is being transfered
|
||||
item.Status = DownloadItemStatus.Downloading;
|
||||
break;
|
||||
|
||||
default: // new status in API? default to downloading
|
||||
item.Message = "Unknown download state: " + torrent.State;
|
||||
_logger.Warn(item.Message);
|
||||
item.Status = DownloadItemStatus.Downloading;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
{
|
||||
var priority = (RTorrentPriority)(remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority);
|
||||
|
||||
_proxy.AddTorrentFromUrl(magnetLink, Settings.MovieCategory, priority, Settings.MovieDirectory, Settings);
|
||||
_proxy.AddTorrentFromUrl(magnetLink, Settings.MovieCategory, priority, Settings.MovieDirectory, Settings.DontStartAutomatically, Settings);
|
||||
|
||||
var tries = 10;
|
||||
var retryDelay = 500;
|
||||
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
{
|
||||
var priority = (RTorrentPriority)(remoteMovie.Movie.IsRecentMovie ? Settings.RecentMoviePriority : Settings.OlderMoviePriority);
|
||||
|
||||
_proxy.AddTorrentFromFile(filename, fileContent, Settings.MovieCategory, priority, Settings.MovieDirectory, Settings);
|
||||
_proxy.AddTorrentFromFile(filename, fileContent, Settings.MovieCategory, priority, Settings.MovieDirectory, Settings.DontStartAutomatically, Settings);
|
||||
|
||||
var tries = 10;
|
||||
var retryDelay = 500;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@@ -13,8 +13,8 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
string GetVersion(RTorrentSettings settings);
|
||||
List<RTorrentTorrent> GetTorrents(RTorrentSettings settings);
|
||||
|
||||
void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, RTorrentSettings settings);
|
||||
void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, RTorrentSettings settings);
|
||||
void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, bool doNotStart, RTorrentSettings settings);
|
||||
void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, bool doNotStart, RTorrentSettings settings);
|
||||
void RemoveTorrent(string hash, RTorrentSettings settings);
|
||||
bool HasHashTorrent(string hash, RTorrentSettings settings);
|
||||
}
|
||||
@@ -24,9 +24,15 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
[XmlRpcMethod("d.multicall2")]
|
||||
object[] TorrentMulticall(params string[] parameters);
|
||||
|
||||
[XmlRpcMethod("load.normal")]
|
||||
int Load(string target, string data, params string[] commands);
|
||||
|
||||
[XmlRpcMethod("load.start")]
|
||||
int LoadStart(string target, string data, params string[] commands);
|
||||
|
||||
[XmlRpcMethod("load.raw")]
|
||||
int LoadRaw(string target, byte[] data, params string[] commands);
|
||||
|
||||
[XmlRpcMethod("load.raw_start")]
|
||||
int LoadRawStart(string target, byte[] data, params string[] commands);
|
||||
|
||||
@@ -102,26 +108,50 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
return items;
|
||||
}
|
||||
|
||||
public void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, RTorrentSettings settings)
|
||||
public void AddTorrentFromUrl(string torrentUrl, string label, RTorrentPriority priority, string directory, bool doNotStart, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote method: load.normal");
|
||||
_logger.Debug("Adding Torrent From URL");
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var response = client.LoadStart("", torrentUrl, GetCommands(label, priority, directory));
|
||||
var response = -1;
|
||||
|
||||
if (doNotStart)
|
||||
{
|
||||
_logger.Debug("Executing remote method load.normal");
|
||||
response = client.Load("", torrentUrl, GetCommands(label, priority, directory));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Executing remote method load.start");
|
||||
response = client.LoadStart("", torrentUrl, GetCommands(label, priority, directory));
|
||||
}
|
||||
|
||||
if (response != 0)
|
||||
{
|
||||
throw new DownloadClientException("Could not add torrent: {0}.", torrentUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, RTorrentSettings settings)
|
||||
public void AddTorrentFromFile(string fileName, byte[] fileContent, string label, RTorrentPriority priority, string directory, bool doNotStart, RTorrentSettings settings)
|
||||
{
|
||||
_logger.Debug("Executing remote method: load.raw");
|
||||
_logger.Debug("Loading Torrent from File");
|
||||
|
||||
var client = BuildClient(settings);
|
||||
|
||||
var response = client.LoadRawStart("", fileContent, GetCommands(label, priority, directory));
|
||||
var response = -1;
|
||||
|
||||
if (doNotStart)
|
||||
{
|
||||
_logger.Debug("Executing remote method load.raw");
|
||||
response = client.LoadRaw("", fileContent, GetCommands(label, priority, directory));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Executing remote method load.raw_start");
|
||||
response = client.LoadRawStart("", fileContent, GetCommands(label, priority, directory));
|
||||
}
|
||||
|
||||
if (response != 0)
|
||||
{
|
||||
throw new DownloadClientException("Could not add torrent: {0}.", fileName);
|
||||
@@ -202,4 +232,4 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
|
||||
[FieldDefinition(9, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(RTorrentPriority), HelpText = "Priority to use when grabbing movies that released over 21 days ago")]
|
||||
public int OlderMoviePriority { get; set; }
|
||||
|
||||
[FieldDefinition(10, Label = "Don't start download automatically", Type = FieldType.Checkbox, Advanced = true, HelpText = "Add Download in a stopped state. This is useful for letting a Queue manager like pyrotorque automatically start the download.")]
|
||||
public bool DontStartAutomatically { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Download.Pending
|
||||
|
||||
public List<PendingRelease> AllByMovieId(int movieId)
|
||||
{
|
||||
return Query.Where(p => p.MovieId == movieId);
|
||||
return Query(q => q.Where(p => p.MovieId == movieId).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,20 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||
|
||||
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem)
|
||||
{
|
||||
if (downloadItem.DownloadId.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Warn("The following download client item ({0}) has no download hash (id), so it cannot be tracked: {1}",
|
||||
downloadClient.Name, downloadItem.Title);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (downloadItem.Title.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Warn("The following download client item ({0}) has no title so it cannot be tracked: {1}",
|
||||
downloadClient.Name, downloadItem.Title);
|
||||
return null;
|
||||
}
|
||||
|
||||
var existingItem = Find(downloadItem.DownloadId);
|
||||
|
||||
if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -34,17 +34,17 @@ namespace NzbDrone.Core.Extras.Files
|
||||
|
||||
public List<TExtraFile> GetFilesByMovie(int movieId)
|
||||
{
|
||||
return Query.Where(c => c.MovieId == movieId);
|
||||
return Query(q => q.Where(c => c.MovieId == movieId).ToList());
|
||||
}
|
||||
|
||||
public List<TExtraFile> GetFilesByMovieFile(int movieFileId)
|
||||
{
|
||||
return Query.Where(c => c.MovieFileId == movieFileId);
|
||||
return Query(q => q.Where(c => c.MovieFileId == movieFileId).ToList());
|
||||
}
|
||||
|
||||
public TExtraFile FindByPath(string path)
|
||||
{
|
||||
return Query.Where(c => c.RelativePath == path).SingleOrDefault();
|
||||
return Query(q => q.Where(c => c.RelativePath == path).SingleOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
32
src/NzbDrone.Core/HealthCheck/Checks/PTPOldSettingsCheck.cs
Normal file
32
src/NzbDrone.Core/HealthCheck/Checks/PTPOldSettingsCheck.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Indexers.PassThePopcorn;
|
||||
|
||||
namespace NzbDrone.Core.HealthCheck.Checks
|
||||
{
|
||||
public class PTPOldSettingsCheck : HealthCheckBase
|
||||
{
|
||||
private readonly IIndexerFactory _indexerFactory;
|
||||
|
||||
public PTPOldSettingsCheck(IIndexerFactory indexerFactory)
|
||||
{
|
||||
_indexerFactory = indexerFactory;
|
||||
}
|
||||
|
||||
public override HealthCheck Check()
|
||||
{
|
||||
var ptpIndexers = _indexerFactory.All().Where(i => i.Settings.GetType() == typeof(PassThePopcornSettings));
|
||||
|
||||
var ptpIndexerOldSettings = ptpIndexers
|
||||
.Where(i => (i.Settings as PassThePopcornSettings).APIUser.IsNullOrWhiteSpace()).Select(i => i.Name);
|
||||
|
||||
if (ptpIndexerOldSettings.Count() > 0)
|
||||
{
|
||||
return new HealthCheck(GetType(), HealthCheckResult.Warning, $"The following PassThePopcorn indexers have deprecated settings and should be updated: {string.Join(",", ptpIndexerOldSettings)}");
|
||||
}
|
||||
|
||||
return new HealthCheck(GetType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||
|
||||
private readonly IHttpRequestBuilderFactory _cloudRequestBuilder;
|
||||
|
||||
public ProxyCheck(ISonarrCloudRequestBuilder cloudRequestBuilder, IConfigService configService, IHttpClient client, Logger logger)
|
||||
public ProxyCheck(IRadarrCloudRequestBuilder cloudRequestBuilder, IConfigService configService, IHttpClient client, Logger logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_client = client;
|
||||
|
||||
@@ -30,37 +30,37 @@ namespace NzbDrone.Core.History
|
||||
|
||||
public List<QualityModel> GetBestQualityInHistory(int movieId)
|
||||
{
|
||||
var history = Query.Where(c => c.MovieId == movieId);
|
||||
var history = Query(q => q.Where(c => c.MovieId == movieId).ToList());
|
||||
|
||||
return history.Select(h => h.Quality).ToList();
|
||||
}
|
||||
|
||||
public History MostRecentForDownloadId(string downloadId)
|
||||
{
|
||||
return Query.Where(h => h.DownloadId == downloadId)
|
||||
return Query(q => q.Where(h => h.DownloadId == downloadId)
|
||||
.OrderByDescending(h => h.Date)
|
||||
.FirstOrDefault();
|
||||
.FirstOrDefault());
|
||||
}
|
||||
|
||||
public List<History> FindByDownloadId(string downloadId)
|
||||
{
|
||||
return Query.Where(h => h.DownloadId == downloadId);
|
||||
return Query(q => q.Where(h => h.DownloadId == downloadId).ToList());
|
||||
}
|
||||
|
||||
public List<History> FindDownloadHistory(int idMovieId, QualityModel quality)
|
||||
{
|
||||
return Query.Where(h =>
|
||||
return Query(q => q.Where(h =>
|
||||
h.MovieId == idMovieId &&
|
||||
h.Quality == quality &&
|
||||
(h.EventType == HistoryEventType.Grabbed ||
|
||||
h.EventType == HistoryEventType.DownloadFailed ||
|
||||
h.EventType == HistoryEventType.DownloadFolderImported)
|
||||
).ToList();
|
||||
).ToList());
|
||||
}
|
||||
|
||||
public List<History> FindByMovieId(int movieId)
|
||||
{
|
||||
return Query.Where(h => h.MovieId == movieId);
|
||||
return Query(q => q.Where(h => h.MovieId == movieId).ToList());
|
||||
}
|
||||
|
||||
public void DeleteForMovie(int movieId)
|
||||
@@ -77,9 +77,9 @@ namespace NzbDrone.Core.History
|
||||
|
||||
public History MostRecentForMovie(int movieId)
|
||||
{
|
||||
return Query.Where(h => h.MovieId == movieId)
|
||||
return Query(q => q.Where(h => h.MovieId == movieId)
|
||||
.OrderByDescending(h => h.Date)
|
||||
.FirstOrDefault();
|
||||
.FirstOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
WHERE Id IN (
|
||||
SELECT Id FROM MetadataFiles
|
||||
WHERE RelativePath
|
||||
@@ -25,6 +25,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
OR RelativePath
|
||||
LIKE '/%'
|
||||
)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM NamingConfig
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM NamingConfig
|
||||
WHERE ID NOT IN (
|
||||
SELECT ID FROM NamingConfig
|
||||
LIMIT 1)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,15 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM Users
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM Users
|
||||
WHERE ID NOT IN (
|
||||
SELECT ID FROM Users
|
||||
LIMIT 1)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,28 +19,32 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
private void DeleteDuplicateMovieMetadata()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
WHERE Id IN (
|
||||
SELECT Id FROM MetadataFiles
|
||||
WHERE Type = 1
|
||||
GROUP BY MovieId, Consumer
|
||||
HAVING COUNT(MovieId) > 1
|
||||
)");
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteDuplicateMovieFileMetadata()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
WHERE Id IN (
|
||||
SELECT Id FROM MetadataFiles
|
||||
WHERE Type = 1
|
||||
GROUP BY MovieFileId, Consumer
|
||||
HAVING COUNT(MovieFileId) > 1
|
||||
)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,16 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM AlternativeTitles
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM AlternativeTitles
|
||||
WHERE Id IN (
|
||||
SELECT AlternativeTitles.Id FROM AlternativeTitles
|
||||
LEFT OUTER JOIN Movies
|
||||
ON AlternativeTitles.MovieId = Movies.Id
|
||||
WHERE Movies.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,16 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM Blacklist
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM Blacklist
|
||||
WHERE Id IN (
|
||||
SELECT Blacklist.Id FROM Blacklist
|
||||
LEFT OUTER JOIN Movies
|
||||
ON Blacklist.MovieId = Movies.Id
|
||||
WHERE Movies.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,16 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
private void CleanupOrphanedByMovie()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM History
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM History
|
||||
WHERE Id IN (
|
||||
SELECT History.Id FROM History
|
||||
LEFT OUTER JOIN Movies
|
||||
ON History.MovieId = Movies.Id
|
||||
WHERE Movies.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,16 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM IndexerStatus
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM IndexerStatus
|
||||
WHERE Id IN (
|
||||
SELECT IndexerStatus.Id FROM IndexerStatus
|
||||
LEFT OUTER JOIN Indexers
|
||||
ON IndexerStatus.IndexerId = Indexers.Id
|
||||
WHERE Indexers.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,38 +20,44 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
private void DeleteOrphanedByMovie()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
WHERE Id IN (
|
||||
SELECT MetadataFiles.Id FROM MetadataFiles
|
||||
LEFT OUTER JOIN Movies
|
||||
ON MetadataFiles.MovieId = Movies.Id
|
||||
WHERE Movies.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteOrphanedByMovieFile()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
WHERE Id IN (
|
||||
SELECT MetadataFiles.Id FROM MetadataFiles
|
||||
LEFT OUTER JOIN MovieFiles
|
||||
ON MetadataFiles.MovieFileId = MovieFiles.Id
|
||||
WHERE MetadataFiles.MovieFileId > 0
|
||||
AND MovieFiles.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteWhereMovieFileIsZero()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MetadataFiles
|
||||
WHERE Id IN (
|
||||
SELECT Id FROM MetadataFiles
|
||||
WHERE Type IN (1, 2)
|
||||
AND MovieFileId = 0)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,15 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MovieFiles
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM MovieFiles
|
||||
WHERE Id IN (
|
||||
SELECT MovieFiles.Id FROM MovieFiles
|
||||
LEFT OUTER JOIN Movies
|
||||
ON MovieFiles.Id = Movies.MovieFileId
|
||||
WHERE Movies.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,16 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM PendingReleases
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM PendingReleases
|
||||
WHERE Id IN (
|
||||
SELECT PendingReleases.Id FROM PendingReleases
|
||||
LEFT OUTER JOIN Movies
|
||||
ON PendingReleases.MovieId = Movies.Id
|
||||
WHERE Movies.Id IS NULL)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,18 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
using (var mapper = _database.GetDataMapper())
|
||||
{
|
||||
|
||||
var usedTags = new[] { "Movies", "Notifications", "DelayProfiles", "Restrictions" }
|
||||
.SelectMany(v => GetUsedTags(v, mapper))
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
var usedTags = new[] {"Movies", "Notifications", "DelayProfiles", "Restrictions", "NetImport"}
|
||||
.SelectMany(v => GetUsedTags(v, mapper))
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
var usedTagsList = string.Join(",", usedTags.Select(d => d.ToString()).ToArray());
|
||||
var usedTagsList = string.Join(",", usedTags.Select(d => d.ToString()).ToArray());
|
||||
|
||||
mapper.ExecuteNonQuery($"DELETE FROM Tags WHERE NOT Id IN ({usedTagsList})");
|
||||
mapper.ExecuteNonQuery($"DELETE FROM Tags WHERE NOT Id IN ({usedTagsList})");
|
||||
}
|
||||
}
|
||||
|
||||
private int[] GetUsedTags(string table, IDataMapper mapper)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user