1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-11 20:28:20 -04:00

Compare commits

...

83 Commits

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

* Keep indentation consistent with current code

* Initialize set of empty tags

* Add tags from list to movie

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

resolves #3419

* Update CustomFormatService.cs

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

* Adding new CheckForFinishedDownloadInterval to UI

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

* Use string interpolation to build url

* Adapt changes by markus101 over at Sonarr

* Remove blank line

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

Fixes #3486

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

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

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

Ref #2296
2019-02-24 17:58:19 +01:00
Leonardo Galli
bd969e0bc3 Fixed: Build errors due to dotnet library. 2019-02-24 00:34:23 +01:00
hatharry
3e96fe4a72 Fixed: Emby library update (#3318)
Fixes: #3158
2019-02-18 11:12:34 +01:00
tobsen987
19299ad47f Fixed: Prevent NullRef in CustomScript on Grab for Indexer (#3323)
fixes #3313
2019-02-18 11:10:22 +01:00
Leonardo Galli
8902a3ca44 @cosmetic removed deploy 2019-02-18 11:07:51 +01:00
Leonardo Galli
4015ff08a6 @cosmetic Added Parsing Library: A dotnet library that "exports" our parsing interface. 2019-02-18 00:09:41 +01:00
Leonardo Galli
9bc50749ae Update README.md 2019-01-31 11:41:07 +01:00
Leonardo Galli
34271605c3 @cosmetic Merge pull request #3339 from hotio/patch-2
Update docker link in README
2019-01-31 11:31:26 +01:00
hotio
8272a160d2 Update docker link in README 2019-01-28 10:20:42 +01:00
Leonardo Galli
e7ad09cf62 Fixed: Hopefully fixed sqlite errors when finding by title. 2019-01-10 16:07:41 +01:00
Leonardo Galli
420cbf6dd0 @cosmetic updated changelog. 2019-01-10 08:39:13 +01:00
Leonardo Galli
02eb30b8ee Fixed: A lot of memory issues, such as IDisposable leakage and leaking all the media covers. (#3227)
Thanks again to @Taloth
2019-01-10 08:36:34 +01:00
Leonardo Galli
49b1f2a67d New: Use APIKey & APIUser for authenticating to PassThePopcorn. (#3264) 2018-12-30 14:17:26 +01:00
Swizzy
7c90667965 Added: Support for forcedUP status (#3277)
Also added a warning message upon hitting new unknown states so that they can be handled properly at some point
2018-12-30 14:17:03 +01:00
Leonardo Galli
6d3cff85ae Fixed: Unable to parse movies from 1800s.
Fixes #3271
2018-12-30 13:55:45 +01:00
Leonardo Galli
b9aba5f424 @cosmetic Updated readme to include roadmap. 2018-12-30 13:32:56 +01:00
Leonardo Galli
47b481e797 Fixed: OSX Packages not getting correct version info
Fixes #3274
2018-12-30 13:29:44 +01:00
Taloth Saldono
3ef224ed1d Fixed: Another IDisposable leak when lazy loading properties. 2018-12-26 15:50:06 +01:00
Leonardo Galli
44b1252ecc Fixed: npm start not working with node 10
Fixes #3258
2018-12-24 15:56:53 +01:00
Leonardo Galli
44842a4e6b Fixed: Hopefully fixed issue where a null downloadId or title would cause no downloads to be tracked.
Fixes #3260
2018-12-24 14:49:33 +01:00
Leonardo Galli
cd520b0341 Fixed: MediaCoverService tests and stupidly forgetting to open the database connection for logging. 2018-12-14 18:48:36 +01:00
Leonardo Galli
fed4a0aebe Fixed: MediaCovers resizing potentially leaking memory when concurrently executing. 2018-12-14 09:55:14 +01:00
lps-rocks
ff894d5210 New: rTorrent - Don't start download automatically (#3222) 2018-12-07 11:26:26 +01:00
Qstick
92b5822a39 New: Remove Pre, postbot, xpost suffixes from release groups (#3220) 2018-12-07 11:22:06 +01:00
Qstick
cbdea30a6e New: Secure URLs for Links and Services (#3219) 2018-12-07 11:21:43 +01:00
Qstick
969ef5c515 Fixed: Bump default version to prevent update running from source (#3199) 2018-12-07 11:20:54 +01:00
Qstick
5b52115d68 Fixed: MediaInfo Unit Test Failing due to AudioAdditionalFeatures (#3221) 2018-12-06 12:59:02 +01:00
Leonardo Galli
899bd086ec Fixed: Stream leakage inside CurlHttpDispatcher 2018-12-02 19:24:16 +01:00
Leonardo Galli
d02d71c336 Fixed: Apparently Microsoft thinks that you should cast to IDisposable first. 2018-12-02 19:04:28 +01:00
Leonardo Galli
d4061bd13c Fixed: Invalid SQLite cache size. 2018-12-02 18:22:18 +01:00
Leonardo Galli
c83995adc1 Fixed: Resource leakage inside HttpClient. 2018-12-02 18:16:05 +01:00
Leonardo Galli
df18c34878 Fixed: Typo that could probably lead to an infinite loop. 2018-12-02 18:14:52 +01:00
Leonardo Galli
eb077b043e Fixed: Resource leakage inside ManagedHttpDispatcher. 2018-12-02 18:14:21 +01:00
Leonardo Galli
42015d5d95 Fixed: Leaking of objects when logging something to the database. 2018-12-02 18:12:03 +01:00
Leonardo Galli
09899fcf6c Fixed: DataMapper potentially leaking stuff when being disposed. 2018-12-02 18:10:57 +01:00
Leonardo Galli
8e7b718209 Fixed: DataMapper not being disposed, leading to resource leakage. 2018-12-02 18:10:14 +01:00
Leonardo Galli
d38562664d Fixed: Memory leak due to unmanaged Bitmaps leaking. 2018-12-02 17:59:15 +01:00
FuNK3Y
abf738ffee Merge branch 'develop' into AddMetadataURL 2018-11-29 20:46:04 +01:00
Leonardo Galli
77950645af @cosmetic add yarn to circleci image 2018-11-25 01:03:50 +01:00
Leonardo Galli
60a9be71bc @cosmetic fix deploy 2018-11-24 19:54:36 +01:00
Leonardo Galli
49ee288dae @cosmetic forgot this 2018-11-24 19:47:37 +01:00
Leonardo Galli
443995cd93 Merge branch 'develop' of https://github.com/Radarr/Radarr into develop 2018-11-24 19:20:02 +01:00
Leonardo Galli
1456200717 @cosmetic added auto deploy for prs and branch builds 2018-11-24 19:19:53 +01:00
Leonardo Galli
28155b09a0 @cosmetic Hopefully made circle ci artifacts compatible with hotios docker 2018-11-24 16:31:53 +01:00
Leonardo Galli
9ba1d26f05 @cosmetic updated release changelog templates. 2018-11-20 11:18:55 +01:00
Leonardo Galli
e439fb00b5 As requested
Co-Authored-By: FuNK3Y <FuNK3Y@users.noreply.github.com>
2018-11-10 16:20:39 +01:00
Leonardo Galli
e1fa7440da Update src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs
Co-Authored-By: FuNK3Y <FuNK3Y@users.noreply.github.com>
2018-11-10 16:16:50 +01:00
Leonardo Galli
e0e531c287 @cosmetic Updated changelog. 2018-11-07 20:59:37 +01:00
FuNK3Y
24cff4d6ee Update XbmcMetadata.cs
Fix typo
2018-10-14 14:24:36 +02:00
FuNK3Y
0df5cd478b Update XbmcMetadataSettings.cs
Fix typo
2018-10-14 14:24:00 +02:00
FuN_K3Y
3a55b766c3 Add imdb url, added setting, fix movie.nfo being renamed on movie rename 2018-10-14 09:59:57 +02:00
170 changed files with 4037 additions and 2777 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -3,6 +3,78 @@
## (unreleased)
### **New features**
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Tags support to NetImport (Lists) ([#3127](https://github.com/Radarr/Radarr/issues/3127)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Improved templates for h264 & h265 custom formats ([#3432](https://github.com/Radarr/Radarr/issues/3432)) [<a href="https://github.com/RhinoRhys">RhinoRhys</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Logo-256.png to a transparent version so it looks better in Android notifications. ([#3479](https://github.com/Radarr/Radarr/issues/3479)) [<a href="https://github.com/jwildman16">jwildman16</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Radarr_Download_Id and Radarr_Download_Client to the environment ([#3276](https://github.com/Radarr/Radarr/issues/3276)) [<a href="https://github.com/Logan">Logan</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Allow CheckForFinishedDownloadInterval to be set from the UI ([#3233](https://github.com/Radarr/Radarr/issues/3233)) [<a href="https://github.com/Steven Crouchman">Steven Crouchman</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Added support for Gotify notifications ([#3474](https://github.com/Radarr/Radarr/issues/3474)) [<a href="https://github.com/stephanrenggli">stephanrenggli</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Remote poster and fanart references to Kodi metadata file ([#2837](https://github.com/Radarr/Radarr/issues/2837)) ([#3302](https://github.com/Radarr/Radarr/issues/3302)) [<a href="https://github.com/RobinQ124274">RobinQ124274</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Support Krypton Kodi Unique Ids ([#3388](https://github.com/Radarr/Radarr/issues/3388)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Adjust Max Slider Value for Qualities ([#3393](https://github.com/Radarr/Radarr/issues/3393)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) README.md ([#3409](https://github.com/Radarr/Radarr/issues/3409)) [<a href="https://github.com/hotio">hotio</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Nzb Validation and Nzbget/SAB URLBase ([#3380](https://github.com/Radarr/Radarr/issues/3380)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) README.md. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) docker link in README. [<a href="https://github.com/hotio">hotio</a>]
### **Fixes**
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Solve ambiguous naming ([#3417](https://github.com/Radarr/Radarr/issues/3417)) [<a href="https://github.com/Viserius">Viserius</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Copy to clipboard not working with calendar feed ([#3495](https://github.com/Radarr/Radarr/issues/3495)) [<a href="https://github.com/Michael Poutre">Michael Poutre</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Edition Tags Not Showing in UI ([#3389](https://github.com/Radarr/Radarr/issues/3389)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Support new feed url format IPTorrents ([#573](https://github.com/Radarr/Radarr/issues/573)) ([#3390](https://github.com/Radarr/Radarr/issues/3390)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCovers Race condition which leads to fanart not being downloaded. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Cannot Add ITA or ITALIAN custom format ([#3385](https://github.com/Radarr/Radarr/issues/3385)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OsInfo for real this time. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Error in unicode cleanup code removing most non-latin characters instead of just invalid ones. ([#3383](https://github.com/Radarr/Radarr/issues/3383)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Forced Subs not parsed by SubtitleLanguageRegex ([#3384](https://github.com/Radarr/Radarr/issues/3384)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OsInfo being renamed to PlatformInfo. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Word Boundary on Edition ([#3382](https://github.com/Radarr/Radarr/issues/3382)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Mis-classification of releases as being Czech ([#3378](https://github.com/Radarr/Radarr/issues/3378)) [<a href="https://github.com/Václav Slavík">Václav Slavík</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Match MBluray releases ([#3358](https://github.com/Radarr/Radarr/issues/3358)) [<a href="https://github.com/Pieter Janssens">Pieter Janssens</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Mono bug causing memory leakage when http connections use gzip compression. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Build errors due to dotnet library. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Emby library update ([#3318](https://github.com/Radarr/Radarr/issues/3318)) [<a href="https://github.com/hatharry">hatharry</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Prevent NullRef in CustomScript on Grab for Indexer ([#3323](https://github.com/Radarr/Radarr/issues/3323)) [<a href="https://github.com/tobsen987">tobsen987</a>]
## v0.2.0.1293 (2019-01-10)
### **New features**
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Use APIKey & APIUser for authenticating to PassThePopcorn. ([#3264](https://github.com/Radarr/Radarr/issues/3264)) [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Support for forcedUP status ([#3277](https://github.com/Radarr/Radarr/issues/3277)) [<a href="https://github.com/Swizzy">Swizzy</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) rTorrent - Don't start download automatically ([#3222](https://github.com/Radarr/Radarr/issues/3222)) [<a href="https://github.com/lps-rocks">lps-rocks</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Remove Pre, postbot, xpost suffixes from release groups ([#3220](https://github.com/Radarr/Radarr/issues/3220)) [<a href="https://github.com/Qstick">Qstick</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Secure URLs for Links and Services ([#3219](https://github.com/Radarr/Radarr/issues/3219)) [<a href="https://github.com/Qstick">Qstick</a>]
### **Fixes**
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Hopefully fixed sqlite errors when finding by title. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Another IDisposable leak when lazy loading properties. [<a href="https://github.com/Taloth Saldono">Taloth Saldono</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCoverService tests and stupidly forgetting to open the database connection for logging. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCovers resizing potentially leaking memory when concurrently executing. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Stream leakage inside CurlHttpDispatcher. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Apparently Microsoft thinks that you should cast to IDisposable first. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Invalid SQLite cache size. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Resource leakage inside HttpClient. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Typo that could probably lead to an infinite loop. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Resource leakage inside ManagedHttpDispatcher. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Leaking of objects when logging something to the database. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) DataMapper potentially leaking stuff when being disposed. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) DataMapper not being disposed, leading to resource leakage. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Memory leak due to unmanaged Bitmaps leaking. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Unable to parse movies from 1800s. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OSX Packages not getting correct version info. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) npm start not working with node 10. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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**
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) 64bit mediainfo.dll to 32bit to resolve issue: https://github.com/Radarr/Radarr/issues/3138. [<a href="https://github.com/geogolem">geogolem</a>]
- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) 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>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Don't hide custom formats behind advanced settings when editing quality. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) 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>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) 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>]
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) 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 @@
- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) "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**
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) UpdateMovieQualityService Tests. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Unable to update custom formats for releases with bad Source Titles. [<a href="https://github.com/Leonardo Galli">Leonardo Galli</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Do not search movie if unmonitored ([#3131](https://github.com/Radarr/Radarr/issues/3131)) [<a href="https://github.com/Ricardo Amaral">Ricardo Amaral</a>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]
- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) 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>]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -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
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat-square)](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
[![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases)
[![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
Branch | develop (stable) | nightly (semi-unstable) |
---|---|---
Binary Releases | [![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases) | [![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
Docker (linuxserver.io, x86_64, arm64, armhf) | [![Docker release](https://img.shields.io/badge/linuxserver-radarr:latest-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr) | [![Docker nightly](https://img.shields.io/badge/linuxserver-radarr:nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr)
Docker (hotio, see [here](https://github.com/hotio/docker-radarr) for more information) | [![Docker release / nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://hub.docker.com/r/hotio/radarr) | [![Docker release / nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://hub.docker.com/r/hotio/radarr)
[![Docker release](https://img.shields.io/badge/docker-release-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr)
[![Docker nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/hotio/suitarr)
[![Docker armhf](https://img.shields.io/badge/docker-armhf-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr)
[![Docker aarch64](https://img.shields.io/badge/docker-aarch64-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
## Support
@@ -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)

View File

@@ -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(() => {

View File

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

View File

@@ -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
View File

7
deploy.sh Normal file
View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}
}

View 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
View 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>

View File

@@ -2,4 +2,4 @@
using System.Reflection;
[assembly: AssemblyVersion("0.1.0.*")]
[assembly: AssemblyVersion("10.0.0.*")]

View File

@@ -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;
}
}

View File

@@ -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;
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -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; }
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
@@ -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)

View File

@@ -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)
{

View File

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

View File

@@ -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);

View File

@@ -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" />

View File

@@ -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("")]

View File

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

View File

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

View File

@@ -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();
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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.

View File

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

View File

@@ -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();
}

View File

@@ -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));

View File

@@ -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");

View File

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

View File

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

View File

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

View File

@@ -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);

View File

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

View File

@@ -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)
{

View File

@@ -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());
}
}
}

View File

@@ -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));

View File

@@ -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)

View File

@@ -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)

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}

View File

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

View File

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

View File

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

View File

@@ -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;

View File

@@ -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;
}
}
}
}

View File

@@ -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));

View File

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

View File

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

View File

@@ -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());
}
}
}

View File

@@ -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)

View File

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

View File

@@ -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());
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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());
}
}
}

View File

@@ -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;

View File

@@ -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());
}
}
}

View File

@@ -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 '/%'
)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}
}

View File

@@ -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
)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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)");
}
}
}
}

View File

@@ -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