1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-16 21:15:28 -04:00

Compare commits

...

118 Commits

Author SHA1 Message Date
Taloth Saldono
5613ab05e0 Fixed: Sabnzbd/NzbGet not processing history items properly after last update. 2017-03-31 18:56:45 +02:00
Taloth Saldono
372442af2c fixed broken tests. 2017-03-30 23:20:49 +02:00
Taloth Saldono
28c45f941b Cleanup of commented out code. 2017-03-30 22:28:00 +02:00
Marcelo Castagna
ea1616586f Fixed: Import from torrent Download Station should move since DS maintains an internal copy for seeding. 2017-03-30 22:26:11 +02:00
Mark McDowall
e48600da42 New: TvMaze and IMDB IDs added to custom script environment variables 2017-03-29 18:22:14 -07:00
Mark McDowall
5d9d2e684e New: Paths for deleted files when upgrading an existing file 2017-03-29 13:22:37 -07:00
Mark McDowall
2e392e0f5e New: Additional variables for custom script on grab events 2017-03-29 13:12:37 -07:00
Mark McDowall
83370ddbbb New: Episode files sent to Recycling Bin are put into subfolders
Closes #401
2017-03-29 06:44:50 -07:00
Mark McDowall
c20b152c28 Fixed spelling in message 2017-03-26 13:21:29 -07:00
Mark McDowall
bf5067466d Guard against a null file showing an exception in release rejections
Fixes #1755
2017-03-26 13:01:59 -07:00
Taloth Saldono
ec7f749541 Tweaked default config for extra files import. 2017-03-26 21:22:58 +02:00
Taloth Saldono
56ecbf4a31 Fixed: Sabnzbd error when tv sorting enabled for all categories. 2017-03-26 17:09:22 +02:00
Mark McDowall
1b39911135 True/False for config settings value 2017-03-25 22:18:57 -07:00
Mark McDowall
6aaefae2d5 New: Explicit toggle for importing extra files 2017-03-25 09:13:28 -07:00
margaale
db9d601115 Revert Session name 2017-03-23 13:46:01 -03:00
Taloth Saldono
e7331539f0 Fixed: Newznab default capabilities erroneously cached if indexer is unavailable. 2017-03-23 17:12:10 +01:00
Taloth Saldono
58bd57bed6 New: Updated MediaInfo to 0.7.93. 2017-03-22 19:17:55 +01:00
Mark McDowall
7a58082cd7 smallicon for Join notifications
New: White icon with transparent background for Join notifications notification bar icon
Closes #1458
2017-03-19 23:31:50 -07:00
Taloth Saldono
2e08f195e4 Fixed: Zero length file causes MediaInfo hanging in 100% cpu load. 2017-03-19 22:02:52 +01:00
Taloth Saldono
a1a5e29c3e fixed sab tests. 2017-03-19 19:00:05 +01:00
margaale
5033886b90 Fixed: DownloadStation api client for DSM 5.x. 2017-03-19 18:50:56 +01:00
Mark McDowall
29419d6575 Update README.md 2017-03-18 23:34:37 -07:00
Mark McDowall
3c22f68f5a Fixed: Parsing releases with year added to the end of the series title
Fixes #1768
2017-03-18 22:45:47 -07:00
Mark McDowall
a0d98951aa Use MaterialisingResponse for static resource responses 2017-03-18 12:22:44 -07:00
Taloth Saldono
70f7404499 Fixed: Sabnzbd 2.0 api compatibility.
closes #1775
2017-03-18 16:32:13 +01:00
Mark McDowall
abd70f5381 New: UHD category for RARBG 2017-03-17 07:16:24 -07:00
Mark McDowall
878e973081 Fixed: Join grab messages
Fixes #1751
2017-03-13 19:43:07 -07:00
Taloth Saldono
2bf3b9e7dd fixed typo setting custom directory for rtorrent. 2017-03-12 11:18:51 +01:00
Taloth Saldono
2326db0dea Fixed: Refactored rtorrent interface to fix reliability issues with adding magnets & torrents.
fixes #1745
2017-03-11 12:15:42 +01:00
Taloth Saldono
3590fedeaf Fixed: Timing issue in rtorrent handling of magnet links.
ref #1745
2017-03-10 21:07:08 +01:00
Taloth Saldono
f4866cae69 fixed broken project file. 2017-03-10 20:43:16 +01:00
Mark McDowall
149d191f62 Remove NCrunch.Framework 2017-03-09 20:30:39 -08:00
Jamie Magee
bb9bd63382 Upgrade CommonServiceLocator
From 1.0 to 1.3
2017-03-09 20:30:39 -08:00
Jamie Magee
34fda24124 Upgrade Microsoft.AspNet.SignalR.Client
From 1.2.1 to 1.2.2
2017-03-09 20:30:39 -08:00
Jamie Magee
c8d10829a0 Upgrade Selenium.*
From 3.0.1 to 3.2.0
2017-03-09 19:49:05 -08:00
Jamie Magee
ae2bdb757a Upgrade NUnit
From 3.5.0 to 3.6.0
2017-03-09 19:49:02 -08:00
Jamie Magee
714ad075fc Upgrade FluentAssertions
From 4.18.0 to 4.19.0
2017-03-09 19:48:11 -08:00
Jamie Magee
87a05df2fd Upgrade TinyTwitter
From 1.1.1 to 1.1.2

NOTE: Sonarr was already using a modified version of TinyTwitter 1.1.2.
This change just modifies the packages.config file to reflect that
2017-03-09 19:48:11 -08:00
Jamie Magee
f3263efa52 Upgrade SharpRaven
From 2.1.0 to 2.2.0
2017-03-09 19:48:11 -08:00
Jamie Magee
1cad11d207 Upgrade Ical.Net
From 2.2.25 to 2.2.32
2017-03-09 19:48:10 -08:00
Jamie Magee
781df8b20a Upgrade NLog
From 4.4.1 to 4.4.3
2017-03-09 19:48:10 -08:00
Mark McDowall
ebcce05588 Fixed: Parsing headers that have a trailing semi-colon
Fixes #1749
2017-03-09 15:40:13 -08:00
Taloth Saldono
bbf2134fe1 Fixed: Deluge 1.3.14 API support due to changed json-rpc checks.
fixes #1738
2017-03-06 20:14:34 +01:00
Mark McDowall
081c5fc332 Broken ExtraFiles migration due to extentionless files
Fixed: Prevent extensionless files from being imported
Fixed: Broken migration due to extensionless extra files
2017-03-06 11:00:38 -08:00
Mark McDowall
47915d5e05 Fixed: Bad extension when importing extra files 2017-03-05 17:45:35 -08:00
Mark McDowall
47e221d9a0 Fixed: Delay profiles are no longer hidden under advanced settings 2017-03-03 21:16:29 -08:00
Mark McDowall
bf485f6f2c Log number of files found when getting video/non-video files 2017-03-03 20:57:05 -08:00
Mark McDowall
b365d8a537 Include language in suffix when importing 2017-03-03 19:44:31 -08:00
Taloth Saldono
fee8da88a6 Accept full language name as suffix. 2017-03-03 19:44:31 -08:00
Mark McDowall
cc0dbf1af4 New: Rename subtitles and extra files when renaming files
Towards #459
2017-03-03 19:44:31 -08:00
Mark McDowall
836131ebb1 New: Import subtitles and extra files when importing media files 2017-03-03 19:44:31 -08:00
Marcelo Castagna
9a870a3709 Fixed: DownloadStation interface stuck in infinite loop in some cases.
* removed empty spaces. changed dcaex => ex

* Changed error message

* changed error message

* Wrong message, ups

* Another message
2017-03-01 18:46:16 +01:00
Taloth Saldono
afe05189da Fixed series scan tests. 2017-02-28 21:06:41 +01:00
Taloth Saldono
2abaef16f1 Fixed Indexer Health Checks and tests. 2017-02-28 20:59:22 +01:00
Daniel Smith
37d5a3f2ad Fixed: Clear EpisodeFile records from database if Series folder is missing, but root folder appears to be mounted. 2017-02-28 17:01:12 +01:00
Mark McDowall
be4d70e3a9 Fixed: Health check failing and preventing others from running 2017-02-28 00:12:34 -08:00
Mark McDowall
79043f2c64 Improve indexer health check messages
Fixed: Improve health check message when all enabled indexers are disabled due to failures
Closes #1551
2017-02-28 00:12:34 -08:00
Mark McDowall
1dab0aee6a Fixed: Reduce parameters required to add a new series
Fixes #1403
2017-02-27 21:37:33 -08:00
Mark McDowall
9b162f2d5e Fixed: Clean RSS feed before detecting type
Fixes #1518
2017-02-27 21:37:00 -08:00
Mark McDowall
5518cf5362 Added Download decision comparator test to confirm quality is preferred over seeders 2017-02-25 16:18:00 -08:00
Taloth Saldono
f7e3d9b4c2 Fixed: DownloadStation regression in queue detection. 2017-02-23 08:58:50 +01:00
Taloth Saldono
6d9a952bd1 Fixed: DownloadStation proxy failing if non-bt/nzb downloads exist. 2017-02-22 19:10:39 +01:00
margaale
3501e33722 turn task type enum into string 2017-02-22 14:10:12 -03:00
margaale
fa89d33900 Fix for key not found, returning a generic error instead 2017-02-22 14:10:12 -03:00
Mark McDowall
0af48fb2e8 Fixed: NZBGet delete:scan treated as failure
Fixes #1394
2017-02-22 00:31:51 -08:00
Mark McDowall
7e9f0d0522 Updated analytics help text 2017-02-21 11:18:29 -08:00
Taloth Saldono
1f8bd8e1e9 Fixed typo in DL station hint text. 2017-02-21 18:19:55 +01:00
Taloth Saldono
2855090005 Fixed: Removed Womble indexer. 2017-02-21 17:03:10 +01:00
Taloth Saldono
060b9f6fd1 Fixed: Updated BTN api url. 2017-02-21 16:40:20 +01:00
margaale
9304547c95 Test if the OutputPath specified by TvDirectory/TvCategory exists. 2017-02-21 16:40:16 +01:00
margaale
c56c83e169 New: Added support for nzb downloads in Synology Download Station. 2017-02-20 18:57:11 +01:00
Mark McDowall
c6fa883662 Fixed: Saving nyaa settings
Fixes #1687
2017-02-16 09:19:28 -08:00
Mark McDowall
4043d07ab1 Verify LimeTorrents parsing 2017-02-15 22:30:03 -08:00
Mark McDowall
8af3348e7f Fixed: Slow loading root folders caused them to never appear 2017-02-15 22:30:03 -08:00
Taloth Saldono
49d0d4c357 Renamed DownloadStation implementation to TorrentDownloadStation. 2017-02-15 21:32:25 +01:00
Taloth Saldono
47b1157b96 Fixed: Permanently removed kickass rss/api implementation. 2017-02-15 21:32:21 +01:00
Taloth Saldono
adc79f0eba Added more sensible error for BTN html response. 2017-02-15 20:40:32 +01:00
Taloth Saldono
6b117427f8 Fixed double question mark in log. 2017-02-15 20:40:32 +01:00
Mark McDowall
7884dd9a39 New: Added omgwtfnzbs Newznab prefix 2017-02-13 22:46:26 -08:00
Marcelo Castagna
45d8b1e2ad Fixed: Delete data when removing torrent from Download Station
fixes #1676
2017-02-13 20:17:52 +01:00
Marcelo Castagna
cf306f4aba Throw exception with error message return by diskstation (#1672) 2017-02-12 20:20:16 +01:00
Mark McDowall
d7aa23388e New: Update Media info for Windows/macOS to 0.7.92.1 2017-02-11 16:29:49 -08:00
margaale
82a99b7f80 New: Added support for Synology Download Station as torrent client. 2017-02-11 21:06:23 +01:00
Taloth Saldono
2f6d9e191e Fixed: Ignore .nfs* files during copy actions since those files are special NFS files that should never be touched.
fixes #1552
2017-02-09 19:33:28 +01:00
Taloth Saldono
0782a15979 Remove backslashes from BTN release titles.
fixes #1075
2017-02-09 19:33:28 +01:00
vertigo235
ddd119a4eb New: Add paused option for NZBGet
Closes #346
2017-02-08 20:36:39 -08:00
Taloth Saldono
d4788b4cae Added tests for edge-case.
closes #1147
2017-02-08 22:10:30 +01:00
Taloth Saldono
812999423b Fixed: Don't try to show diskspace usage non-existing drives.
fixes #1639
2017-02-07 23:06:14 +01:00
Taloth Saldono
657730f4d2 Fixed: /var/lib/docker no longer shows up in DiskSpace. Caused warnings if the user used docker with zfs storage driver.
fixes #1663
2017-02-07 22:44:31 +01:00
Taloth Saldono
0255eb3aca Fixed: Increased timeout when waiting for rtorrent to finish adding torrent.
fixes #1665
2017-02-07 22:36:47 +01:00
Mark McDowall
fc15daa37e New: Improve parsing of audio channels from MediaInfo output 2017-02-04 22:04:12 -08:00
Mark McDowall
10264a5bfb New: Ensure folders are sorted alphabetically when importing
Closes #294
2017-02-04 22:04:12 -08:00
Mark McDowall
ef044f1ff5 Update README.md 2017-01-27 20:56:07 -08:00
Mark McDowall
ef03e9e9a7 Fixed: Proper port validation for download clients and connections
Closes #1642
2017-01-26 22:35:16 -08:00
Mark McDowall
3bd7c09acf Strip 2160p from titles before parsing 2017-01-23 23:53:15 -08:00
Keivan Beigi
fbd2f8dea4 Fixed: Growl download notification title 2017-01-22 13:07:21 -08:00
Keivan Beigi
15e07f72d4 Better Runtime names 2017-01-20 20:54:04 -08:00
Keivan Beigi
f25bfe9d28 don't log migrations during regular DB tests 2017-01-20 20:33:10 -08:00
Keivan Beigi
d5e720c404 include os name, runtime name in version tag for sentry 2017-01-20 20:16:34 -08:00
Keivan Beigi
c9a8ebc2e6 Create anonymous hash to detect issue duplication 2017-01-20 20:15:49 -08:00
Mark McDowall
5e7e816c03 AsOsAgnostic paths for root folder tests 2017-01-20 09:02:36 -08:00
vertigo235
f56076a135 Fixed: Pushover silent priority 2017-01-19 23:51:58 -08:00
Mark McDowall
54dd527f01 Exclude .grab and Plex Version folders 2017-01-19 01:38:37 -08:00
Mark McDowall
c6eb19c04d Exclude .grab and Plex Version folders
New: Ignore .grab folder (Plex DVR)
New: Ignore Plex Versions folder (Media Optimizer)
Closes #1610
2017-01-18 20:15:32 -08:00
Mitchell Cash
38b65ba27d Cleanup README (#1622) 2017-01-18 12:31:20 -08:00
Keivan Beigi
a2a49ce934 Revert "New: Upgraded SQLite binares for macOS"
This reverts commit 8d91f18823.
2017-01-18 10:04:36 -08:00
Keivan Beigi
047d5a4388 Revert "New: Upgraded SQLite binaries for Windows (3.16.0)"
This reverts commit 111e401a2c.
2017-01-18 10:04:26 -08:00
Keivan Beigi
aae69ff49a Revert "Upgraded System.Data.SQLite to 1.0.104.0"
This reverts commit 01e2f4e7e5.
2017-01-18 10:04:07 -08:00
Sander Ploegsma
da451cfe03 Option to convert ical feed items to all-day events 2017-01-17 22:36:48 +01:00
Keivan Beigi
01e2f4e7e5 Upgraded System.Data.SQLite to 1.0.104.0 2017-01-17 11:47:46 -08:00
Keivan Beigi
8aacc61c50 New: Switched nyaa.se to HTTPS 2017-01-17 11:47:46 -08:00
Keivan Beigi
111e401a2c New: Upgraded SQLite binaries for Windows (3.16.0) 2017-01-17 11:47:45 -08:00
Keivan
8d91f18823 New: Upgraded SQLite binares for macOS
Upgraded from 3.8.1 to 3.9.1
2017-01-17 11:47:45 -08:00
Keivan Beigi
cea6469ab8 Use nameof 2017-01-17 11:47:06 -08:00
Mark McDowall
ced7a7dce2 New: Prefer anime batch releases over single episode releases 2017-01-14 12:28:22 -08:00
Mitchell Cash
20a2cfe260 Use DOGnzb name as the default rather than the URL 2017-01-14 08:45:29 -08:00
Drew Freyling
5b0a285b84 New: Reduced image file sizes 2017-01-12 13:10:19 -08:00
Mark McDowall
68ea8a551c Fixed: Parsing of SABnzbd develop version 2017-01-12 00:38:56 -08:00
291 changed files with 6658 additions and 2084 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 707 B

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 34 KiB

BIN
Logo/96-Outline-White.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

52
README.md Normal file
View File

@@ -0,0 +1,52 @@
# Sonarr
Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
## Major Features Include:
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
* Automatically detects new episodes
* Can scan your existing library and download any missing episodes
* Can watch for better quality of the episodes you already have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
* Automatic failed download handling will try another release if one fails
* Manual search so you can pick any release or to see why a release was not downloaded automatically
* Fully configurable episode renaming
* Full integration with SABnzbd and NZBGet
* Full integration with Kodi, Plex (notification, library update, metadata)
* Full support for specials and multi-episode releases
* And a beautiful UI
## Configuring Development Environment:
### Requirements
* Visual Studio 2015 (https://www.visualstudio.com/vs/)
* [Git](https://git-scm.com/downloads)
* [NodeJS](https://nodejs.org/en/download/)
### Setup
* Make sure all the required software mentioned above are installed.
* Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
* Grab the submodules `git submodule init && git submodule update`
* Install the required Node Packages `npm install`
* Start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
*Please note gulp must be running at all times while you are working with Sonarr client source files.*
### Development
* Open `NzbDrone.sln` in Visual Studio
* Make sure `NzbDrone.Console` is set as the startup project
### License
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
* Copyright 2010-2017
### Sponsors
* [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
* [ReSharper](http://www.jetbrains.com/resharper/)
* [WebStorm](http://www.jetbrains.com/webstorm/)
* [TeamCity](http://www.jetbrains.com/teamcity/)

View File

@@ -1,53 +0,0 @@
# Sonarr #
Sonarr is a PVR for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new episodes of your favorite shows and will grab, sort and rename them. It can also be configured to automatically upgrade the quality of files already downloaded when a better quality format becomes available.
## Major Features Include: ##
* Support for major platforms: Windows, Linux, OSX, Raspberry Pi, etc.
* Automatically detects new episodes
* Can scan your existing library and download any missing episodes
* Can watch for better quality of the episodes you already have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
* Automatic failed download handling will try another release if one fails
* Manual search so you can pick any release or to see why a release was not downloaded automatically
* Fully configurable episode renaming
* Full integration with SABNzbd and NzbGet
* Full integration with XBMC, Plex (notification, library update, metadata)
* Full support for specials and multi-episode releases
* And a beautiful UI
## Configuring Development Environment: ##
### Requirements ###
- Visual Studio 2015 [Free Community Edition](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx)
- [Git](http://git-scm.com/downloads)
- [NodeJS](http://nodejs.org/download/)
### Setup ###
- Make sure all the required software mentioned above are installed.
- Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
- Grab the submodules `git submodule init && git submodule update`
- install the required Node Packages `npm install`
- start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
*Please note gulp must be running at all times while you are working with Sonarr client source files.*
### Development ###
- Open `NzbDrone.sln` in Visual Studio
- Make sure `NzbDrone.Console` is set as the startup project
### License ###
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
Copyright 2010-2016
### Sponsors ###
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
- [ReSharper](http://www.jetbrains.com/resharper/)
- [WebStorm](http://www.jetbrains.com/webstorm/)
- [TeamCity](http://www.jetbrains.com/teamcity/)

View File

@@ -52,8 +52,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
</packages>

View File

@@ -42,17 +42,17 @@
<HintPath>..\packages\NBuilder.4.0.0\lib\net40\FizzWare.NBuilder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FluentAssertions, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions.Core, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>
<Private>True</Private>
<Reference Include="Moq, Version=4.2.1510.2205, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FluentAssertions" version="4.18.0" targetFramework="net40" />
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
<package id="Moq" version="4.0.10827" />
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
<package id="NUnit" version="3.6.0" targetFramework="net40" />
</packages>

View File

@@ -37,6 +37,7 @@ namespace NzbDrone.Api.Calendar
var end = DateTime.Today.AddDays(futureDays);
var unmonitored = false;
var premiersOnly = false;
var asAllDay = false;
var tags = new List<int>();
// TODO: Remove start/end parameters in v3, they don't work well for iCal
@@ -46,6 +47,7 @@ namespace NzbDrone.Api.Calendar
var queryFutureDays = Request.Query.FutureDays;
var queryUnmonitored = Request.Query.Unmonitored;
var queryPremiersOnly = Request.Query.PremiersOnly;
var queryAsAllDay = Request.Query.AsAllDay;
var queryTags = Request.Query.Tags;
if (queryStart.HasValue) start = DateTime.Parse(queryStart.Value);
@@ -73,6 +75,11 @@ namespace NzbDrone.Api.Calendar
premiersOnly = bool.Parse(queryPremiersOnly.Value);
}
if (queryAsAllDay.HasValue)
{
asAllDay = bool.Parse(queryAsAllDay.Value);
}
if (queryTags.HasValue)
{
var tagInput = (string)queryTags.Value.ToString();
@@ -102,11 +109,19 @@ namespace NzbDrone.Api.Calendar
var occurrence = calendar.Create<Event>();
occurrence.Uid = "NzbDrone_episode_" + episode.Id;
occurrence.Status = episode.HasFile ? EventStatus.Confirmed : EventStatus.Tentative;
occurrence.Start = new CalDateTime(episode.AirDateUtc.Value) { HasTime = true };
occurrence.End = new CalDateTime(episode.AirDateUtc.Value.AddMinutes(episode.Series.Runtime)) { HasTime = true };
occurrence.Description = episode.Overview;
occurrence.Categories = new List<string>() { episode.Series.Network };
if (asAllDay)
{
occurrence.Start = new CalDateTime(episode.AirDateUtc.Value) { HasTime = false };
}
else
{
occurrence.Start = new CalDateTime(episode.AirDateUtc.Value) { HasTime = true };
occurrence.End = new CalDateTime(episode.AirDateUtc.Value.AddMinutes(episode.Series.Runtime)) { HasTime = true };
}
switch (episode.Series.SeriesType)
{
case SeriesTypes.Daily:

View File

@@ -73,14 +73,14 @@ namespace NzbDrone.Api.ClientSchema
if (propertyInfo.PropertyType == typeof(int))
{
var value = Convert.ToInt32(field.Value);
propertyInfo.SetValue(target, value, null);
var value = field.Value.ToString().ParseInt32();
propertyInfo.SetValue(target, value ?? 0, null);
}
else if (propertyInfo.PropertyType == typeof(long))
{
var value = Convert.ToInt64(field.Value);
propertyInfo.SetValue(target, value, null);
var value = field.Value.ToString().ParseInt64();
propertyInfo.SetValue(target, value ?? 0, null);
}
else if (propertyInfo.PropertyType == typeof(int?))

View File

@@ -20,6 +20,7 @@ namespace NzbDrone.Api.Config
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
public bool CopyUsingHardlinks { get; set; }
public bool ImportExtraFiles { get; set; }
public string ExtraFileExtensions { get; set; }
public bool EnableMediaInfo { get; set; }
}
@@ -44,6 +45,7 @@ namespace NzbDrone.Api.Config
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
CopyUsingHardlinks = model.CopyUsingHardlinks,
ImportExtraFiles = model.ImportExtraFiles,
ExtraFileExtensions = model.ExtraFileExtensions,
EnableMediaInfo = model.EnableMediaInfo
};

View File

@@ -2,6 +2,8 @@
using System.IO;
using NLog;
using NzbDrone.Api.REST;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
@@ -16,6 +18,7 @@ namespace NzbDrone.Api.EpisodeFiles
IHandle<EpisodeFileAddedEvent>
{
private readonly IMediaFileService _mediaFileService;
private readonly IDiskProvider _diskProvider;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly ISeriesService _seriesService;
private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
@@ -23,6 +26,7 @@ namespace NzbDrone.Api.EpisodeFiles
public EpisodeFileModule(IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService,
IDiskProvider diskProvider,
IRecycleBinProvider recycleBinProvider,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
@@ -30,6 +34,7 @@ namespace NzbDrone.Api.EpisodeFiles
: base(signalRBroadcaster)
{
_mediaFileService = mediaFileService;
_diskProvider = diskProvider;
_recycleBinProvider = recycleBinProvider;
_seriesService = seriesService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
@@ -74,9 +79,10 @@ namespace NzbDrone.Api.EpisodeFiles
var episodeFile = _mediaFileService.Get(id);
var series = _seriesService.GetSeries(episodeFile.SeriesId);
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));
_logger.Info("Deleting episode file: {0}", fullPath);
_recycleBinProvider.DeleteFile(fullPath);
_recycleBinProvider.DeleteFile(fullPath, subfolder);
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
}

View File

@@ -39,7 +39,7 @@ namespace NzbDrone.Api.Extensions.Pipelines
context.Items["ApiRequestStartTime"] = DateTime.UtcNow;
var reqPath = GetRequestPathAndQuery(context.Request);
_loggerHttp.Trace("Req: {0} [{1}] {2}", id, context.Request.Method, reqPath);
return null;
@@ -80,7 +80,7 @@ namespace NzbDrone.Api.Extensions.Pipelines
{
if (request.Url.Query.IsNotNullOrWhiteSpace())
{
return string.Concat(request.Url.Path, "?", request.Url.Query);
return string.Concat(request.Url.Path, request.Url.Query);
}
else
{
@@ -88,4 +88,4 @@ namespace NzbDrone.Api.Extensions.Pipelines
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using NLog;
using Nancy;
@@ -38,7 +38,7 @@ namespace NzbDrone.Api.Frontend.Mappers
if (_diskProvider.FileExists(filePath, _caseSensitive))
{
var response = new StreamResponse(() => GetContentStream(filePath), MimeTypes.GetMimeType(filePath));
return response;
return new MaterialisingResponse(response);
}
_logger.Warn("File {0} not found", filePath);

View File

@@ -41,20 +41,17 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="antlr.runtime, Version=2.7.6.2, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.25\lib\net40\antlr.runtime.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\Ical.Net.2.2.32\lib\net40\antlr.runtime.dll</HintPath>
</Reference>
<Reference Include="FluentValidation, Version=6.2.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\FluentValidation.6.2.1.0\lib\portable-net40+sl50+wp80+win8+wpa81\FluentValidation.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ical.Net, Version=2.1.0.30332, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.25\lib\net40\Ical.Net.dll</HintPath>
<Private>True</Private>
<Reference Include="Ical.Net, Version=2.1.0.18776, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.32\lib\net40\Ical.Net.dll</HintPath>
</Reference>
<Reference Include="Ical.Net.Collections, Version=2.1.0.30331, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.25\lib\net40\Ical.Net.Collections.dll</HintPath>
<Private>True</Private>
<Reference Include="Ical.Net.Collections, Version=2.1.0.18775, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.32\lib\net40\Ical.Net.Collections.dll</HintPath>
</Reference>
<Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
@@ -73,12 +70,10 @@
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="NodaTime, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4226afe0d9b296d1, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.25\lib\net40\NodaTime.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\Ical.Net.2.2.32\lib\net40\NodaTime.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -41,7 +41,7 @@ namespace NzbDrone.Api.Series
public static List<Season> ToModel(this IEnumerable<SeasonResource> resources)
{
return resources.Select(ToModel).ToList();
return resources?.Select(ToModel).ToList() ?? new List<Season>();
}
}
}

View File

@@ -29,12 +29,14 @@ namespace NzbDrone.Api.Series
{
private readonly ISeriesService _seriesService;
private readonly IAddSeriesService _addSeriesService;
private readonly ISeriesStatisticsService _seriesStatisticsService;
private readonly ISceneMappingService _sceneMappingService;
private readonly IMapCoversToLocal _coverMapper;
public SeriesModule(IBroadcastSignalRMessage signalRBroadcaster,
ISeriesService seriesService,
IAddSeriesService addSeriesService,
ISeriesStatisticsService seriesStatisticsService,
ISceneMappingService sceneMappingService,
IMapCoversToLocal coverMapper,
@@ -48,6 +50,7 @@ namespace NzbDrone.Api.Series
: base(signalRBroadcaster)
{
_seriesService = seriesService;
_addSeriesService = addSeriesService;
_seriesStatisticsService = seriesStatisticsService;
_sceneMappingService = sceneMappingService;
@@ -74,7 +77,6 @@ namespace NzbDrone.Api.Series
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.Title).NotEmpty();
PostValidator.RuleFor(s => s.TvdbId).GreaterThan(0).SetValidator(seriesExistsValidator);
PutValidator.RuleFor(s => s.Path).IsValidPath();
@@ -114,7 +116,7 @@ namespace NzbDrone.Api.Series
{
var model = seriesResource.ToModel();
return _seriesService.AddSeries(model).Id;
return _addSeriesService.AddSeries(model).Id;
}
private void UpdateSeries(SeriesResource seriesResource)

View File

@@ -207,19 +207,9 @@ namespace NzbDrone.Api.Series
public static Core.Tv.Series ToModel(this SeriesResource resource, Core.Tv.Series series)
{
series.TvdbId = resource.TvdbId;
var updatedSeries = resource.ToModel();
series.Seasons = resource.Seasons.ToModel();
series.Path = resource.Path;
series.ProfileId = resource.ProfileId;
series.SeasonFolder = resource.SeasonFolder;
series.Monitored = resource.Monitored;
series.SeriesType = resource.SeriesType;
series.RootFolderPath = resource.RootFolderPath;
series.Tags = resource.Tags;
series.AddOptions = resource.AddOptions;
series.ApplyChanges(updatedSeries);
return series;
}

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FluentValidation" version="6.2.1.0" targetFramework="net40" />
<package id="Ical.Net" version="2.2.25" targetFramework="net40" />
<package id="Ical.Net" version="2.2.32" targetFramework="net40" />
<package id="Nancy" version="1.4.3" targetFramework="net40" />
<package id="Nancy.Authentication.Basic" version="1.4.1" targetFramework="net40" />
<package id="Nancy.Authentication.Forms" version="1.4.1" targetFramework="net40" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
</packages>

View File

@@ -41,21 +41,17 @@
<HintPath>..\packages\NBuilder.4.0.0\lib\net40\FizzWare.NBuilder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FluentAssertions, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions.Core, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>
<Private>True</Private>
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FluentAssertions" version="4.18.0" targetFramework="net40" />
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
<package id="Moq" version="4.0.10827" />
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
<package id="NUnit" version="3.6.0" targetFramework="net40" />
</packages>

View File

@@ -38,21 +38,17 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="FluentAssertions, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions.Core, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>
<Private>True</Private>
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -62,13 +58,11 @@
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="WebDriver, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Selenium.WebDriver.3.0.1\lib\net40\WebDriver.dll</HintPath>
<Private>True</Private>
<Reference Include="WebDriver, Version=3.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Selenium.WebDriver.3.2.0\lib\net40\WebDriver.dll</HintPath>
</Reference>
<Reference Include="WebDriver.Support, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Selenium.Support.3.0.1\lib\net40\WebDriver.Support.dll</HintPath>
<Private>True</Private>
<Reference Include="WebDriver.Support, Version=3.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Selenium.Support.3.2.0\lib\net40\WebDriver.Support.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FluentAssertions" version="4.18.0" targetFramework="net40" />
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
<package id="Selenium.Support" version="3.0.1" targetFramework="net40" />
<package id="Selenium.WebDriver" version="3.0.1" targetFramework="net40" />
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
<package id="NUnit" version="3.6.0" targetFramework="net40" />
<package id="Selenium.Support" version="3.2.0" targetFramework="net40" />
<package id="Selenium.WebDriver" version="3.2.0" targetFramework="net40" />
</packages>

View File

@@ -16,6 +16,7 @@ namespace NzbDrone.Common.Test.DiskTests
private readonly string _targetPath = @"C:\target\my.video.mkv".AsOsAgnostic();
private readonly string _backupPath = @"C:\source\my.video.mkv.backup~".AsOsAgnostic();
private readonly string _tempTargetPath = @"C:\target\my.video.mkv.partial~".AsOsAgnostic();
private readonly string _nfsFile = ".nfs01231232";
[SetUp]
public void SetUp()
@@ -642,6 +643,21 @@ namespace NzbDrone.Common.Test.DiskTests
VerifyCopyFolder(source.FullName, destination.FullName);
}
[Test]
public void CopyFolder_should_ignore_nfs_temp_file()
{
WithRealDiskProvider();
var source = GetFilledTempFolder();
File.WriteAllText(Path.Combine(source.FullName, _nfsFile), "SubFile1");
var destination = new DirectoryInfo(GetTempFilePath());
Subject.TransferFolder(source.FullName, destination.FullName, TransferMode.Copy);
File.Exists(Path.Combine(destination.FullName, _nfsFile)).Should().BeFalse();
}
[Test]
public void MoveFolder_should_move_folder()
@@ -704,6 +720,26 @@ namespace NzbDrone.Common.Test.DiskTests
destination.GetFileSystemInfos().Should().BeEmpty();
}
[Test]
public void MirrorFolder_should_not_remove_nfs_files()
{
WithRealDiskProvider();
var original = GetFilledTempFolder();
var source = new DirectoryInfo(GetTempFilePath());
var destination = new DirectoryInfo(GetTempFilePath());
source.Create();
Subject.TransferFolder(original.FullName, destination.FullName, TransferMode.Copy);
File.WriteAllText(Path.Combine(destination.FullName, _nfsFile), "SubFile1");
var count = Subject.MirrorFolder(source.FullName, destination.FullName);
count.Should().Equals(0);
destination.GetFileSystemInfos().Should().HaveCount(1);
}
[Test]
public void MirrorFolder_should_add_new_files()
{
@@ -721,6 +757,24 @@ namespace NzbDrone.Common.Test.DiskTests
VerifyCopyFolder(original.FullName, destination.FullName);
}
[Test]
public void MirrorFolder_should_ignore_nfs_temp_file()
{
WithRealDiskProvider();
var source = GetFilledTempFolder();
File.WriteAllText(Path.Combine(source.FullName, _nfsFile), "SubFile1");
var destination = new DirectoryInfo(GetTempFilePath());
var count = Subject.MirrorFolder(source.FullName, destination.FullName);
count.Should().Equals(3);
File.Exists(Path.Combine(destination.FullName, _nfsFile)).Should().BeFalse();
}
[Test]
public void MirrorFolder_should_not_touch_equivalent_files()
{

View File

@@ -0,0 +1,21 @@
using FluentAssertions;
using NUnit.Framework;
namespace NzbDrone.Common.Test
{
[TestFixture]
public class HashUtilFixture
{
[Test]
public void should_create_anon_id()
{
HashUtil.AnonymousToken().Should().NotBeNullOrEmpty();
}
[Test]
public void should_create_the_same_id()
{
HashUtil.AnonymousToken().Should().Be(HashUtil.AnonymousToken());
}
}
}

View File

@@ -5,6 +5,7 @@ using System;
using System.Text;
using NzbDrone.Common.Http;
using System.Collections.Specialized;
using System.Linq;
namespace NzbDrone.Common.Test.Http
{
@@ -36,5 +37,17 @@ namespace NzbDrone.Common.Test.Http
Action action = () => httpheader.GetEncodingFromContentType();
action.ShouldThrow<ArgumentException>();
}
[Test]
public void should_parse_cookie_with_trailing_semi_colon()
{
var cookies = HttpHeader.ParseCookies("uid=123456; pass=123456b2f3abcde42ac3a123f3f1fc9f;");
cookies.Count.Should().Be(2);
cookies.First().Key.Should().Be("uid");
cookies.First().Value.Should().Be("123456");
cookies.Last().Key.Should().Be("pass");
cookies.Last().Value.Should().Be("123456b2f3abcde42ac3a123f3f1fc9f");
}
}
}

View File

@@ -37,21 +37,17 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="FluentAssertions, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions.Core, Version=4.18.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="FluentAssertions.Core, Version=4.19.0.0, Culture=neutral, PublicKeyToken=33f2691a05b67b6a, processorArchitecture=MSIL">
<HintPath>..\packages\FluentAssertions.4.19.0\lib\net40\FluentAssertions.Core.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>
<Private>True</Private>
<Reference Include="nunit.framework, Version=3.6.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.6.0\lib\net40\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -84,6 +80,7 @@
<Compile Include="ExtensionTests\IEnumerableExtensionTests\ExceptByFixture.cs" />
<Compile Include="ExtensionTests\IEnumerableExtensionTests\IntersectByFixture.cs" />
<Compile Include="ExtensionTests\Int64ExtensionFixture.cs" />
<Compile Include="HashUtilFixture.cs" />
<Compile Include="Http\HttpClientFixture.cs" />
<Compile Include="Http\HttpHeaderFixture.cs" />
<Compile Include="Http\HttpRequestBuilderFixture.cs" />

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FluentAssertions" version="4.18.0" targetFramework="net40" />
<package id="FluentAssertions" version="4.19.0" targetFramework="net40" />
<package id="Moq" version="4.0.10827" />
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
<package id="NUnit" version="3.6.0" targetFramework="net40" />
</packages>

View File

@@ -64,11 +64,15 @@ namespace NzbDrone.Common.Disk
foreach (var subDir in _diskProvider.GetDirectoryInfos(sourcePath))
{
if (ShouldIgnore(subDir)) continue;
result &= TransferFolder(subDir.FullName, Path.Combine(targetPath, subDir.Name), mode, verificationMode);
}
foreach (var sourceFile in _diskProvider.GetFileInfos(sourcePath))
{
if (ShouldIgnore(sourceFile)) continue;
var destFile = Path.Combine(targetPath, sourceFile.Name);
result &= TransferFile(sourceFile.FullName, destFile, mode, true, verificationMode);
@@ -101,11 +105,15 @@ namespace NzbDrone.Common.Disk
foreach (var subDir in targetFolders.Where(v => !sourceFolders.Any(d => d.Name == v.Name)))
{
if (ShouldIgnore(subDir)) continue;
_diskProvider.DeleteFolder(subDir.FullName, true);
}
foreach (var subDir in sourceFolders)
{
if (ShouldIgnore(subDir)) continue;
filesCopied += MirrorFolder(subDir.FullName, Path.Combine(targetPath, subDir.Name));
}
@@ -114,11 +122,15 @@ namespace NzbDrone.Common.Disk
foreach (var targetFile in targetFiles.Where(v => !sourceFiles.Any(d => d.Name == v.Name)))
{
if (ShouldIgnore(targetFile)) continue;
_diskProvider.DeleteFile(targetFile.FullName);
}
foreach (var sourceFile in sourceFiles)
{
if (ShouldIgnore(sourceFile)) continue;
var targetFile = Path.Combine(targetPath, sourceFile.Name);
if (CompareFiles(sourceFile.FullName, targetFile))
@@ -564,5 +576,27 @@ namespace NzbDrone.Common.Disk
throw;
}
}
private bool ShouldIgnore(DirectoryInfo folder)
{
if (folder.Name.StartsWith(".nfs"))
{
_logger.Trace("Ignoring folder {0}", folder.FullName);
return true;
}
return false;
}
private bool ShouldIgnore(FileInfo file)
{
if (file.Name.StartsWith(".nfs"))
{
_logger.Trace("Ignoring file {0}", file.FullName);
return true;
}
return false;
}
}
}

View File

@@ -32,6 +32,19 @@ namespace NzbDrone.Common.EnvironmentInfo
public static bool IsMono => Platform == PlatformType.Mono;
public static bool IsDotNet => Platform == PlatformType.DotNet;
public static string PlatformName
{
get
{
if (IsDotNet)
{
return ".NET";
}
return "Mono";
}
}
public abstract Version Version { get; }
}
}

View File

@@ -2,7 +2,7 @@ using System;
namespace NzbDrone.Common.Extensions
{
public static class Base64Extentions
public static class Base64Extensions
{
public static string ToBase64(this byte[] bytes)
{
@@ -14,4 +14,4 @@ namespace NzbDrone.Common.Extensions
return BitConverter.GetBytes(input).ToBase64();
}
}
}
}

View File

@@ -14,8 +14,8 @@ namespace NzbDrone.Common.Extensions
public static Dictionary<T1, T2> Merge<T1, T2>(this Dictionary<T1, T2> first, Dictionary<T1, T2> second)
{
if (first == null) throw new ArgumentNullException("first");
if (second == null) throw new ArgumentNullException("second");
if (first == null) throw new ArgumentNullException(nameof(first));
if (second == null) throw new ArgumentNullException(nameof(second));
var merged = new Dictionary<T1, T2>();
first.ToList().ForEach(kv => merged[kv.Key] = kv.Value);

View File

@@ -5,11 +5,11 @@ using System.Xml.Linq;
namespace NzbDrone.Common.Extensions
{
public static class XmlExtentions
public static class XmlExtensions
{
public static IEnumerable<XElement> FindDecendants(this XContainer container, string localName)
{
return container.Descendants().Where(c => c.Name.LocalName.Equals(localName, StringComparison.InvariantCultureIgnoreCase));
}
}
}
}

View File

@@ -24,7 +24,13 @@ namespace NzbDrone.Common
}
}
}
return string.Format("{0:x8}", mCrc);
return $"{mCrc:x8}";
}
public static string AnonymousToken()
{
var seed = $"{Environment.ProcessorCount}_{Environment.OSVersion.Platform}_{Environment.MachineName}_{Environment.UserName}";
return HashUtil.CalculateCrc(seed);
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -169,7 +169,7 @@ namespace NzbDrone.Common.Http
public static List<KeyValuePair<string, string>> ParseCookies(string cookies)
{
return cookies.Split(';')
return cookies.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries)
.Select(v => v.Trim().Split('='))
.Select(v => new KeyValuePair<string, string>(v[0], v[1]))
.ToList();

View File

@@ -9,7 +9,7 @@ namespace NzbDrone.Common.Http
public class JsonRpcRequestBuilder : HttpRequestBuilder
{
public static HttpAccept JsonRpcHttpAccept = new HttpAccept("application/json-rpc, application/json");
public static string JsonRpcContentType = "application/json-rpc";
public static string JsonRpcContentType = "application/json";
public string JsonMethod { get; private set; }
public List<object> JsonParameters { get; private set; }

View File

@@ -1,4 +1,3 @@
using System;
using SharpRaven.Data;
namespace NzbDrone.Common.Instrumentation.Sentry
@@ -7,7 +6,7 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
public SentryUser Create()
{
return new SentryUser(Environment.MachineName);
return new SentryUser(HashUtil.AnonymousToken());
}
}
}

View File

@@ -37,13 +37,13 @@ namespace NzbDrone.Common.Instrumentation.Sentry
{
Compression = true,
Environment = RuntimeInfo.IsProduction ? "production" : "development",
Release = BuildInfo.Release
Release = BuildInfo.Release,
ErrorOnCapture = OnError
};
_client.ErrorOnCapture = OnError;
_client.Tags.Add("osfamily", OsInfo.Os.ToString());
_client.Tags.Add("runtime", PlatformInfo.Platform.ToString().ToLower());
_client.Tags.Add("runtime", PlatformInfo.PlatformName);
_client.Tags.Add("culture", Thread.CurrentThread.CurrentCulture.Name);
_client.Tags.Add("branch", BuildInfo.Branch);
_client.Tags.Add("version", BuildInfo.Version.ToString());
@@ -135,10 +135,14 @@ namespace NzbDrone.Common.Instrumentation.Sentry
sentryEvent.Fingerprint.Add(logEvent.Exception.GetType().FullName);
}
var osName = Environment.GetEnvironmentVariable("OS_NAME");
var osVersion = Environment.GetEnvironmentVariable("OS_VERSION");
var runTimeVersion = Environment.GetEnvironmentVariable("RUNTIME_VERSION");
sentryEvent.Tags.Add("os_name", Environment.GetEnvironmentVariable("OS_NAME"));
sentryEvent.Tags.Add("os_version", Environment.GetEnvironmentVariable("OS_VERSION"));
sentryEvent.Tags.Add("runtime_version", Environment.GetEnvironmentVariable("RUNTIME_VERSION"));
sentryEvent.Tags.Add("os_name", osName);
sentryEvent.Tags.Add("os_version", $"{osName} {osVersion}");
sentryEvent.Tags.Add("runtime_version", $"{PlatformInfo.PlatformName} {runTimeVersion}");
_client.Capture(sentryEvent);
}

View File

@@ -44,16 +44,14 @@
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="Org.Mentalis, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DotNet4.SocksProxy.1.3.2.0\lib\net40\Org.Mentalis.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpRaven, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SharpRaven.2.1.0\lib\net40\SharpRaven.dll</HintPath>
<Private>True</Private>
<Reference Include="SharpRaven, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SharpRaven.2.2.0\lib\net40\SharpRaven.dll</HintPath>
</Reference>
<Reference Include="SocksWebProxy, Version=1.3.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DotNet4.SocksProxy.1.3.2.0\lib\net40\SocksWebProxy.dll</HintPath>
@@ -135,14 +133,14 @@
<Compile Include="Expansive\Tree.cs" />
<Compile Include="Expansive\TreeNode.cs" />
<Compile Include="Expansive\TreeNodeList.cs" />
<Compile Include="Extensions\Base64Extentions.cs" />
<Compile Include="Extensions\Base64Extensions.cs" />
<Compile Include="Extensions\DateTimeExtensions.cs" />
<Compile Include="Crypto\HashConverter.cs" />
<Compile Include="Extensions\Int64Extensions.cs" />
<Compile Include="Extensions\ObjectExtensions.cs" />
<Compile Include="Extensions\StreamExtensions.cs" />
<Compile Include="Extensions\UrlExtensions.cs" />
<Compile Include="Extensions\XmlExtentions.cs" />
<Compile Include="Extensions\XmlExtensions.cs" />
<Compile Include="HashUtil.cs" />
<Compile Include="Http\Dispatchers\CurlHttpDispatcher.cs" />
<Compile Include="Http\Dispatchers\FallbackHttpDispatcher.cs" />

View File

@@ -25,7 +25,7 @@ namespace NzbDrone.Common.TPL
/// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param>
public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
{
if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException(nameof(maxDegreeOfParallelism));
_maxDegreeOfParallelism = maxDegreeOfParallelism;
}

View File

@@ -3,6 +3,6 @@
<package id="DotNet4.SocksProxy" version="1.3.2.0" targetFramework="net40" />
<package id="ICSharpCode.SharpZipLib.Patched" version="0.86.5" targetFramework="net40" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="SharpRaven" version="2.1.0" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
<package id="SharpRaven" version="2.2.0" targetFramework="net40" />
</packages>

View File

@@ -79,8 +79,7 @@
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\NLog.4.4.3\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

@@ -3,6 +3,6 @@
<package id="Microsoft.Owin" version="2.1.0" targetFramework="net40" />
<package id="Microsoft.Owin.Hosting" version="2.1.0" targetFramework="net40" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
<package id="NLog" version="4.4.1" targetFramework="net40" />
<package id="NLog" version="4.4.3" targetFramework="net40" />
<package id="Owin" version="1.0" targetFramework="net40" />
</packages>

View File

@@ -0,0 +1,62 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class update_btn_url_migration_fixture : MigrationTest<update_btn_url>
{
[TestCase("http://api.btnapps.net")]
[TestCase("https://api.btnapps.net")]
[TestCase("http://api.btnapps.net/")]
[TestCase("https://api.btnapps.net/")]
public void should_replace_old_url(string oldUrl)
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "btn_old_url",
Implementation = "BroadcastheNet",
Settings = new BroadcastheNetSettings106
{
BaseUrl = oldUrl
}.ToJson(),
ConfigContract = "BroadcastheNetSettings"
});
});
var items = db.Query<IndexerDefinition90>("SELECT * FROM Indexers");
items.Should().HaveCount(1);
items.First().Settings.ToObject<BroadcastheNetSettings106>().BaseUrl.Should().Contain("api.broadcasthe.net");
}
[Test]
public void should_not_replace_other_indexers()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Indexers").Row(new
{
Name = "not_btn",
Implementation = "NotBroadcastheNet",
Settings = new BroadcastheNetSettings106
{
BaseUrl = "http://api.btnapps.net",
}.ToJson(),
ConfigContract = "BroadcastheNetSettings"
});
});
var items = db.Query<IndexerDefinition90>("SELECT * FROM Indexers");
items.Should().HaveCount(1);
items.First().Settings.ToObject<BroadcastheNetSettings106>().BaseUrl.Should().Be("http://api.btnapps.net");
}
}
}

View File

@@ -0,0 +1,83 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class fix_extra_file_extensionsFixture : MigrationTest<fix_extra_file_extension>
{
[Test]
public void should_extra_files_that_do_not_have_an_extension()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("ExtraFiles").Row(new
{
SeriesId = 1,
SeasonNumber = 1,
EpisodeFileId = 1,
RelativePath = "Series.Title.S01E01",
Added = "2016-05-30 20:23:02.3725923",
LastUpdated = "2016-05-30 20:23:02.3725923",
Extension = ""
});
});
var items = db.Query("Select * from ExtraFiles");
items.Should().BeEmpty();
}
[Test]
public void should_fix_double_extension()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("SubtitleFiles").Row(new
{
SeriesId = 1,
SeasonNumber = 1,
EpisodeFileId = 1,
RelativePath = "Series.Title.S01E01.en.srt",
Added = "2016-05-30 20:23:02.3725923",
LastUpdated = "2016-05-30 20:23:02.3725923",
Language = Language.English,
Extension = "en.srt"
});
});
var items = db.Query("Select * from SubtitleFiles");
items.Should().HaveCount(1);
items.First()["Extension"].Should().Be(".srt");
}
[Test]
public void should_fix_extension_missing_a_leading_period()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("ExtraFiles").Row(new
{
SeriesId = 1,
SeasonNumber = 1,
EpisodeFileId = 1,
RelativePath = "Series.Title.S01E01.nfo-orig",
Added = "2016-05-30 20:23:02.3725923",
LastUpdated = "2016-05-30 20:23:02.3725923",
Extension = "nfo-orig"
});
});
var items = db.Query("Select * from ExtraFiles");
items.Should().HaveCount(1);
items.First()["Extension"].Should().Be(".nfo-orig");
}
}
}

View File

@@ -0,0 +1,54 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class import_extra_files_configFixture : MigrationTest<import_extra_files>
{
[Test]
public void should_not_insert_if_missing()
{
var db = WithMigrationTestDb();
var items = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
items.Should().BeNull();
}
[Test]
public void should_not_insert_if_empty()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "extrafileextensions",
Value = ""
});
});
var items = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
items.Should().BeNull();
}
[Test]
public void should_insert_True_if_configured()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "extrafileextensions",
Value = "srt"
});
});
var items = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
items.Should().Be("True");
}
}
}

View File

@@ -0,0 +1,133 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class fix_extra_files_configFixture : MigrationTest<fix_extra_files_config>
{
[Test]
public void should_not_update_importextrafiles_disabled()
{
var db = WithMigrationTestDb();
var itemEnabled = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
itemEnabled.Should().BeNull();
}
[Test]
public void should_fix_importextrafiles_if_wrong()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "importextrafiles",
Value = 1
});
});
var itemEnabled = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
itemEnabled.Should().Be("True");
}
[Test]
public void should_fill_in_default_extensions()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "importextrafiles",
Value = "False"
});
c.Insert.IntoTable("Config").Row(new
{
Key = "extrafileextensions",
Value = ""
});
});
var itemEnabled = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
itemEnabled.Should().Be("False");
var itemExtensions = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'extrafileextensions'");
itemExtensions.Should().Be("srt");
}
[Test]
public void should_not_fill_in_default_extensions()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "importextrafiles",
Value = "True"
});
c.Insert.IntoTable("Config").Row(new
{
Key = "extrafileextensions",
Value = ""
});
});
var itemEnabled = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
itemEnabled.Should().Be("True");
var itemExtensions = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'extrafileextensions'");
itemExtensions.Should().Be("");
}
[Test]
public void should_not_fill_in_default_extensions_if_not_defined()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "importextrafiles",
Value = "False"
});
});
var itemEnabled = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
itemEnabled.Should().Be("False");
var itemExtensions = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'extrafileextensions'");
itemExtensions.Should().BeNull();
}
[Test]
public void should_not_fill_in_default_extensions_if_already_defined()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Config").Row(new
{
Key = "importextrafiles",
Value = "False"
});
c.Insert.IntoTable("Config").Row(new
{
Key = "extrafileextensions",
Value = "sub"
});
});
var itemEnabled = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'importextrafiles'");
itemEnabled.Should().Be("False");
var itemExtensions = db.QueryScalar<string>("SELECT Value FROM Config WHERE Key = 'extrafileextensions'");
itemExtensions.Should().Be("sub");
}
}
}

View File

@@ -217,6 +217,37 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.FullSeason.Should().BeTrue();
}
[Test]
public void should_prefer_multiepisode_over_single_episode_for_anime()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1), GivenEpisode(2) }, new QualityModel(Quality.HDTV720p));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p));
remoteEpisode1.Series.SeriesType = SeriesTypes.Anime;
remoteEpisode2.Series.SeriesType = SeriesTypes.Anime;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.Count.Should().Be(remoteEpisode1.Episodes.Count);
}
[Test]
public void should_prefer_single_episode_over_multi_episode_for_non_anime()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1), GivenEpisode(2) }, new QualityModel(Quality.HDTV720p));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.HDTV720p));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.Count.Should().Be(remoteEpisode2.Episodes.Count);
}
[Test]
public void should_prefer_releases_with_more_seeders()
{
@@ -348,5 +379,34 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Release.Should().Be(remoteEpisode1.Release);
}
[Test]
public void should_prefer_quality_over_the_number_of_peers()
{
var remoteEpisode1 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.Bluray1080p));
var remoteEpisode2 = GivenRemoteEpisode(new List<Episode> { GivenEpisode(1) }, new QualityModel(Quality.SDTV));
var torrentInfo1 = new TorrentInfo();
torrentInfo1.PublishDate = DateTime.Now;
torrentInfo1.DownloadProtocol = DownloadProtocol.Torrent;
torrentInfo1.Seeders = 100;
torrentInfo1.Peers = 10;
torrentInfo1.Size = 200.Megabytes();
var torrentInfo2 = torrentInfo1.JsonClone();
torrentInfo2.Seeders = 1100;
torrentInfo2.Peers = 10;
torrentInfo1.Size = 250.Megabytes();
remoteEpisode1.Release = torrentInfo1;
remoteEpisode2.Release = torrentInfo2;
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
((TorrentInfo)qualifiedReports.First().RemoteEpisode.Release).Should().Be(torrentInfo1);
}
}
}

View File

@@ -45,7 +45,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
};
}
[Test, TestCaseSource("AllowedTestCases")]
[Test, TestCaseSource(nameof(AllowedTestCases))]
public void should_allow_if_quality_is_defined_in_profile(Quality qualityType)
{
remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType;
@@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test, TestCaseSource("DeniedTestCases")]
[Test, TestCaseSource(nameof(DeniedTestCases))]
public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType)
{
remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType;

View File

@@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Returns(autoDownloadPropers);
}
[Test, TestCaseSource("IsUpgradeTestCases")]
[Test, TestCaseSource(nameof(IsUpgradeTestCases))]
public void IsUpgradeTest(Quality current, int currentVersion, Quality newQuality, int newVersion, Quality cutoff, bool expected)
{
GivenAutoDownloadPropers(true);

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DiskSpace;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.DiskSpace
{
[TestFixture]
public class DiskSpaceServiceFixture : CoreTest<DiskSpaceService>
{
private string _seriesFolder;
private string _seriesFolder2;
private string _droneFactoryFolder;
[SetUp]
public void SetUp()
{
_seriesFolder = @"G:\fasdlfsdf\series".AsOsAgnostic();
_seriesFolder2 = @"G:\fasdlfsdf\series2".AsOsAgnostic();
_droneFactoryFolder = @"G:\dronefactory".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetMounts())
.Returns(new List<IMount>());
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetPathRoot(It.IsAny<string>()))
.Returns(@"G:\".AsOsAgnostic());
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetAvailableSpace(It.IsAny<string>()))
.Returns(0);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetTotalSize(It.IsAny<string>()))
.Returns(0);
GivenSeries();
}
private void GivenSeries(params Series[] series)
{
Mocker.GetMock<ISeriesService>()
.Setup(v => v.GetAllSeries())
.Returns(series.ToList());
}
private void GivenExistingFolder(string folder)
{
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FolderExists(folder))
.Returns(true);
}
[Test]
public void should_check_diskspace_for_series_folders()
{
GivenSeries(new Series { Path = _seriesFolder });
GivenExistingFolder(_seriesFolder);
var freeSpace = Subject.GetFreeSpace();
freeSpace.Should().NotBeEmpty();
}
[Test]
public void should_check_diskspace_for_same_root_folder_only_once()
{
GivenSeries(new Series { Path = _seriesFolder }, new Series { Path = _seriesFolder2 });
GivenExistingFolder(_seriesFolder);
GivenExistingFolder(_seriesFolder2);
var freeSpace = Subject.GetFreeSpace();
freeSpace.Should().HaveCount(1);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Once());
}
[Test]
public void should_not_check_diskspace_for_missing_series_folders()
{
GivenSeries(new Series { Path = _seriesFolder });
var freeSpace = Subject.GetFreeSpace();
freeSpace.Should().BeEmpty();
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Never());
}
[Test]
public void should_check_diskspace_for_dronefactory_folder()
{
Mocker.GetMock<IConfigService>()
.SetupGet(v => v.DownloadedEpisodesFolder)
.Returns(_droneFactoryFolder);
GivenExistingFolder(_droneFactoryFolder);
var freeSpace = Subject.GetFreeSpace();
freeSpace.Should().NotBeEmpty();
}
[Test]
public void should_not_check_diskspace_for_missing_dronefactory_folder()
{
Mocker.GetMock<IConfigService>()
.SetupGet(v => v.DownloadedEpisodesFolder)
.Returns(_droneFactoryFolder);
var freeSpace = Subject.GetFreeSpace();
freeSpace.Should().BeEmpty();
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Never());
}
}
}

View File

@@ -99,6 +99,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
var result = Subject.GetItems().Single();
VerifyCompleted(result);
result.CanBeRemoved.Should().BeFalse();
result.CanMoveFiles.Should().BeFalse();
}
[Test]

View File

@@ -77,6 +77,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
var result = Subject.GetItems().Single();
VerifyCompleted(result);
result.CanBeRemoved.Should().BeTrue();
result.CanMoveFiles.Should().BeTrue();
}
[Test]

View File

@@ -19,6 +19,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
protected DelugeTorrent _downloading;
protected DelugeTorrent _failed;
protected DelugeTorrent _completed;
protected DelugeTorrent _seeding;
[SetUp]
public void Setup()
@@ -75,7 +76,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
Size = 1000,
BytesDownloaded = 1000,
Progress = 100.0,
DownloadPath = "somepath"
DownloadPath = "somepath",
IsAutoManaged = true,
StopAtRatio = true,
StopRatio = 1.0,
Ratio = 1.5
};
Mocker.GetMock<ITorrentFileInfoReader>()
@@ -114,7 +119,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
.Returns("CBC2F069FE8BB2F544EAE707D75BCD3DE9DCF951".ToLower())
.Callback(PrepareClientToReturnQueuedItem);
}
protected virtual void GivenTorrents(List<DelugeTorrent> torrents)
{
if (torrents == null)
@@ -129,7 +134,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
protected void PrepareClientToReturnQueuedItem()
{
GivenTorrents(new List<DelugeTorrent>
GivenTorrents(new List<DelugeTorrent>
{
_queued
});
@@ -137,7 +142,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
protected void PrepareClientToReturnDownloadingItem()
{
GivenTorrents(new List<DelugeTorrent>
GivenTorrents(new List<DelugeTorrent>
{
_downloading
});
@@ -145,7 +150,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
protected void PrepareClientToReturnFailedItem()
{
GivenTorrents(new List<DelugeTorrent>
GivenTorrents(new List<DelugeTorrent>
{
_failed
});
@@ -189,6 +194,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
PrepareClientToReturnCompletedItem();
var item = Subject.GetItems().Single();
VerifyCompleted(item);
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
@@ -248,11 +256,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
item.Status.Should().Be(expectedItemStatus);
}
[TestCase(DelugeTorrentStatus.Paused, DownloadItemStatus.Completed, true)]
[TestCase(DelugeTorrentStatus.Checking, DownloadItemStatus.Downloading, true)]
[TestCase(DelugeTorrentStatus.Queued, DownloadItemStatus.Completed, true)]
[TestCase(DelugeTorrentStatus.Seeding, DownloadItemStatus.Completed, true)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(string apiStatus, DownloadItemStatus expectedItemStatus, bool expectedReadOnly)
[TestCase(DelugeTorrentStatus.Paused, DownloadItemStatus.Completed)]
[TestCase(DelugeTorrentStatus.Checking, DownloadItemStatus.Downloading)]
[TestCase(DelugeTorrentStatus.Queued, DownloadItemStatus.Completed)]
[TestCase(DelugeTorrentStatus.Seeding, DownloadItemStatus.Completed)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(string apiStatus, DownloadItemStatus expectedItemStatus)
{
_completed.State = apiStatus;
@@ -261,24 +269,25 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
var item = Subject.GetItems().Single();
item.Status.Should().Be(expectedItemStatus);
item.IsReadOnly.Should().Be(expectedReadOnly);
}
[Test]
public void GetItems_should_check_share_ratio_for_readonly()
[TestCase(0.5, false)]
[TestCase(1.01, true)]
public void GetItems_should_check_share_ratio_for_moveFiles_and_remove(double ratio, bool canBeRemoved)
{
_completed.State = DelugeTorrentStatus.Paused;
_completed.IsAutoManaged = true;
_completed.StopAtRatio = true;
_completed.StopRatio = 1.0;
_completed.Ratio = 1.01;
_completed.Ratio = ratio;
PrepareClientToReturnCompletedItem();
var item = Subject.GetItems().Single();
item.Status.Should().Be(DownloadItemStatus.Completed);
item.IsReadOnly.Should().BeFalse();
item.CanMoveFiles.Should().Be(canBeRemoved);
item.CanBeRemoved.Should().Be(canBeRemoved);
}
[Test]

View File

@@ -0,0 +1,74 @@
using System;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Download.Clients.DownloadStation;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
{
[TestFixture]
public class SerialNumberProviderFixture : CoreTest<SerialNumberProvider>
{
protected DownloadStationSettings _settings;
[SetUp]
protected void Setup()
{
_settings = new DownloadStationSettings();
}
private void GivenValidResponse()
{
Mocker.GetMock<IDSMInfoProxy>()
.Setup(d => d.GetSerialNumber(It.IsAny<DownloadStationSettings>()))
.Returns("serial");
}
private void GivenInvalidResponse()
{
Mocker.GetMock<IDSMInfoProxy>()
.Setup(d => d.GetSerialNumber(It.IsAny<DownloadStationSettings>()))
.Throws(new DownloadClientException("Serial response invalid"));
}
[Test]
public void should_return_hashedserialnumber()
{
GivenValidResponse();
var serial = Subject.GetSerialNumber(_settings);
// This hash should remain the same for 'serial', so don't update the test if you change HashConverter, fix the code instead.
serial.Should().Be("50DE66B735D30738618568294742FCF1DFA52A47");
Mocker.GetMock<IDSMInfoProxy>()
.Verify(d => d.GetSerialNumber(It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void should_cache_serialnumber()
{
GivenValidResponse();
var serial1 = Subject.GetSerialNumber(_settings);
var serial2 = Subject.GetSerialNumber(_settings);
serial2.Should().Be(serial1);
Mocker.GetMock<IDSMInfoProxy>()
.Verify(d => d.GetSerialNumber(It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void should_throw_if_serial_number_unavailable()
{
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetSerialNumber(_settings));
ExceptionVerification.ExpectedWarns(1);
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Download.Clients.DownloadStation;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
{
[TestFixture]
public class SharedFolderResolverFixture : CoreTest<SharedFolderResolver>
{
protected string _serialNumber = "SERIALNUMBER";
protected OsPath _sharedFolder;
protected OsPath _physicalPath;
protected DownloadStationSettings _settings;
[SetUp]
protected void Setup()
{
_sharedFolder = new OsPath("/myFolder");
_physicalPath = new OsPath("/mnt/sda1/folder");
_settings = new DownloadStationSettings();
Mocker.GetMock<IFileStationProxy>()
.Setup(f => f.GetSharedFolderMapping(It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Throws(new DownloadClientException("There is no shared folder"));
Mocker.GetMock<IFileStationProxy>()
.Setup(f => f.GetSharedFolderMapping(_sharedFolder.FullPath, It.IsAny<DownloadStationSettings>()))
.Returns(new SharedFolderMapping(_sharedFolder.FullPath, _physicalPath.FullPath));
}
[Test]
public void should_throw_when_cannot_resolve_shared_folder()
{
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.RemapToFullPath(new OsPath("/unknownFolder"), _settings, _serialNumber));
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_return_valid_sharedfolder()
{
var mapping = Subject.RemapToFullPath(_sharedFolder, _settings, "abc");
mapping.Should().Be(_physicalPath);
Mocker.GetMock<IFileStationProxy>()
.Verify(f => f.GetSharedFolderMapping(It.IsAny<string>(), It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void should_cache_mapping()
{
Subject.RemapToFullPath(_sharedFolder, _settings, "abc");
Subject.RemapToFullPath(_sharedFolder, _settings, "abc");
Mocker.GetMock<IFileStationProxy>()
.Verify(f => f.GetSharedFolderMapping(It.IsAny<string>(), It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void should_remap_subfolder()
{
var mapping = Subject.RemapToFullPath(_sharedFolder + "sub", _settings, "abc");
mapping.Should().Be(_physicalPath + "sub");
}
}
}

View File

@@ -0,0 +1,626 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.DownloadStation;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
{
[TestFixture]
public class TorrentDownloadStationFixture : DownloadClientFixtureBase<TorrentDownloadStation>
{
protected DownloadStationSettings _settings;
protected DownloadStationTask _queued;
protected DownloadStationTask _downloading;
protected DownloadStationTask _failed;
protected DownloadStationTask _completed;
protected DownloadStationTask _seeding;
protected DownloadStationTask _magnet;
protected DownloadStationTask _singleFile;
protected DownloadStationTask _multipleFiles;
protected DownloadStationTask _singleFileCompleted;
protected DownloadStationTask _multipleFilesCompleted;
protected string _serialNumber = "SERIALNUMBER";
protected string _category = "sonarr";
protected string _tvDirectory = @"video/Series";
protected string _defaultDestination = "somepath";
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
protected Dictionary<string, object> _downloadStationConfigItems;
protected string DownloadURL => "magnet:?xt=urn:btih:5dee65101db281ac9c46344cd6b175cdcad53426&dn=download";
[SetUp]
public void Setup()
{
_settings = new DownloadStationSettings()
{
Host = "127.0.0.1",
Port = 5000,
Username = "admin",
Password = "pass"
};
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = _settings;
_queued = new DownloadStationTask()
{
Id = "id1",
Size = 1000,
Status = DownloadStationTaskStatus.Waiting,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "0"},
{ "speed_download", "0" }
}
}
};
_completed = new DownloadStationTask()
{
Id = "id2",
Size = 1000,
Status = DownloadStationTaskStatus.Finished,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
},
}
};
_seeding = new DownloadStationTask()
{
Id = "id2",
Size = 1000,
Status = DownloadStationTaskStatus.Seeding,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
_downloading = new DownloadStationTask()
{
Id = "id3",
Size = 1000,
Status = DownloadStationTaskStatus.Downloading,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "100"},
{ "speed_download", "50" }
}
}
};
_failed = new DownloadStationTask()
{
Id = "id4",
Size = 1000,
Status = DownloadStationTaskStatus.Error,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "10"},
{ "speed_download", "0" }
}
}
};
_singleFile = new DownloadStationTask()
{
Id = "id5",
Size = 1000,
Status = DownloadStationTaskStatus.Seeding,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "a.mkv",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
_multipleFiles = new DownloadStationTask()
{
Id = "id6",
Size = 1000,
Status = DownloadStationTaskStatus.Seeding,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
_singleFileCompleted = new DownloadStationTask()
{
Id = "id6",
Size = 1000,
Status = DownloadStationTaskStatus.Finished,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "a.mkv",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
_multipleFilesCompleted = new DownloadStationTask()
{
Id = "id6",
Size = 1000,
Status = DownloadStationTaskStatus.Finished,
Type = DownloadStationTaskType.BT.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", DownloadURL }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
Mocker.GetMock<ITorrentFileInfoReader>()
.Setup(s => s.GetHashFromTorrentFile(It.IsAny<byte[]>()))
.Returns("CBC2F069FE8BB2F544EAE707D75BCD3DE9DCF951");
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0]));
_downloadStationConfigItems = new Dictionary<string, object>
{
{ "default_destination", _defaultDestination },
};
Mocker.GetMock<IDownloadStationInfoProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems);
}
protected void GivenSharedFolder()
{
Mocker.GetMock<ISharedFolderResolver>()
.Setup(s => s.RemapToFullPath(It.IsAny<OsPath>(), It.IsAny<DownloadStationSettings>(), It.IsAny<string>()))
.Returns<OsPath, DownloadStationSettings, string>((path, setttings, serial) => _physicalPath);
}
protected void GivenSerialNumber()
{
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(It.IsAny<DownloadStationSettings>()))
.Returns(_serialNumber);
}
protected void GivenTvCategory()
{
_settings.TvCategory = _category;
}
protected void GivenTvDirectory()
{
_settings.TvDirectory = _tvDirectory;
}
protected virtual void GivenTasks(List<DownloadStationTask> torrents)
{
if (torrents == null)
{
torrents = new List<DownloadStationTask>();
}
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.GetTasks(It.IsAny<DownloadStationSettings>()))
.Returns(torrents);
}
protected void PrepareClientToReturnQueuedItem()
{
GivenTasks(new List<DownloadStationTask>
{
_queued
});
}
protected void GivenSuccessfulDownload()
{
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000]));
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.AddTaskFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Callback(PrepareClientToReturnQueuedItem);
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Callback(PrepareClientToReturnQueuedItem);
}
protected override RemoteEpisode CreateRemoteEpisode()
{
var episode = base.CreateRemoteEpisode();
episode.Release.DownloadUrl = DownloadURL;
return episode;
}
protected int GivenAllKindOfTasks()
{
var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding };
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(d => d.GetTasks(_settings))
.Returns(tasks);
return tasks.Count;
}
[Test]
public void Download_with_TvDirectory_should_force_directory()
{
GivenSerialNumber();
GivenTvDirectory();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void Download_with_category_should_force_directory()
{
GivenSerialNumber();
GivenTvCategory();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void Download_without_TvDirectory_and_Category_should_use_default()
{
GivenSerialNumber();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void GetItems_should_return_empty_list_if_no_tasks_available()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>());
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_return_ignore_tasks_of_unknown_type()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask> { _completed });
_completed.Type = "ipfs";
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_ignore_downloads_in_wrong_folder()
{
_settings.TvDirectory = @"/shared/folder/sub";
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask> { _completed });
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_throw_if_shared_folder_resolve_fails()
{
Mocker.GetMock<ISharedFolderResolver>()
.Setup(s => s.RemapToFullPath(It.IsAny<OsPath>(), It.IsAny<DownloadStationSettings>(), It.IsAny<string>()))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
GivenSerialNumber();
GivenAllKindOfTasks();
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetItems());
ExceptionVerification.ExpectedErrors(0);
}
[Test]
public void GetItems_should_throw_if_serial_number_unavailable()
{
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
GivenSharedFolder();
GivenAllKindOfTasks();
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetItems());
ExceptionVerification.ExpectedErrors(0);
}
[Test]
public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
{
var remoteEpisode = CreateRemoteEpisode();
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode));
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never());
}
[Test]
public void GetItems_should_set_outputPath_to_base_folder_when_single_file_non_finished_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>() { _singleFile });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().OutputPath.Should().Be(_physicalPath + _singleFile.Title);
}
[Test]
public void GetItems_should_set_outputPath_to_torrent_folder_when_multiple_files_non_finished_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>() { _multipleFiles });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().OutputPath.Should().Be(_physicalPath + _multipleFiles.Title);
}
[Test]
public void GetItems_should_set_outputPath_to_base_folder_when_single_file_finished_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>() { _singleFileCompleted });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().OutputPath.Should().Be(_physicalPath + _singleFileCompleted.Title);
}
[Test]
public void GetItems_should_set_outputPath_to_torrent_folder_when_multiple_files_finished_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>() { _multipleFilesCompleted });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().OutputPath.Should().Be($"{_physicalPath}/{_multipleFiles.Title}");
}
[Test]
public void GetItems_should_not_map_outputpath_for_queued_or_downloading_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>
{
_queued, _downloading
});
var items = Subject.GetItems();
items.Should().HaveCount(2);
items.Should().OnlyContain(v => v.OutputPath.IsEmpty);
}
[Test]
public void GetItems_should_map_outputpath_for_completed_or_failed_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>
{
_completed, _failed, _seeding
});
var items = Subject.GetItems();
items.Should().HaveCount(3);
items.Should().OnlyContain(v => !v.OutputPath.IsEmpty);
}
[TestCase(DownloadStationTaskStatus.Downloading, false, false)]
[TestCase(DownloadStationTaskStatus.Finished, true, true)]
[TestCase(DownloadStationTaskStatus.Seeding, true, false)]
[TestCase(DownloadStationTaskStatus.Waiting, false, false)]
public void GetItems_should_return_canBeMoved_and_canBeDeleted_as_expected(DownloadStationTaskStatus apiStatus, bool canMoveFilesExpected, bool canBeRemovedExpected)
{
GivenSerialNumber();
GivenSharedFolder();
_queued.Status = apiStatus;
GivenTasks(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems();
items.Should().HaveCount(1);
var item = items.First();
item.CanBeRemoved.Should().Be(canBeRemovedExpected);
item.CanMoveFiles.Should().Be(canMoveFilesExpected);
}
[TestCase(DownloadStationTaskStatus.Downloading, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Error, DownloadItemStatus.Failed)]
[TestCase(DownloadStationTaskStatus.Extracting, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Finished, DownloadItemStatus.Completed)]
[TestCase(DownloadStationTaskStatus.Finishing, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.HashChecking, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Paused, DownloadItemStatus.Paused)]
[TestCase(DownloadStationTaskStatus.Seeding, DownloadItemStatus.Completed)]
[TestCase(DownloadStationTaskStatus.Waiting, DownloadItemStatus.Queued)]
public void GetItems_should_return_item_as_downloadItemStatus(DownloadStationTaskStatus apiStatus, DownloadItemStatus expectedItemStatus)
{
GivenSerialNumber();
GivenSharedFolder();
_queued.Status = apiStatus;
GivenTasks(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().Status.Should().Be(expectedItemStatus);
}
}
}

View File

@@ -0,0 +1,434 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.DownloadStation;
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
using NzbDrone.Core.MediaFiles.TorrentInfo;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Test.Common;
using NzbDrone.Core.Organizer;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests
{
[TestFixture]
public class UsenetDownloadStationFixture : DownloadClientFixtureBase<UsenetDownloadStation>
{
protected DownloadStationSettings _settings;
protected DownloadStationTask _queued;
protected DownloadStationTask _downloading;
protected DownloadStationTask _failed;
protected DownloadStationTask _completed;
protected DownloadStationTask _seeding;
protected string _serialNumber = "SERIALNUMBER";
protected string _category = "sonarr";
protected string _tvDirectory = @"video/Series";
protected string _defaultDestination = "somepath";
protected OsPath _physicalPath = new OsPath("/mnt/sdb1/mydata");
protected RemoteEpisode _remoteEpisode;
protected Dictionary<string, object> _downloadStationConfigItems;
[SetUp]
public void Setup()
{
_remoteEpisode = CreateRemoteEpisode();
_settings = new DownloadStationSettings()
{
Host = "127.0.0.1",
Port = 5000,
Username = "admin",
Password = "pass"
};
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = _settings;
_queued = new DownloadStationTask()
{
Id = "id1",
Size = 1000,
Status = DownloadStationTaskStatus.Waiting,
Type = DownloadStationTaskType.NZB.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "0"},
{ "speed_download", "0" }
}
}
};
_completed = new DownloadStationTask()
{
Id = "id2",
Size = 1000,
Status = DownloadStationTaskStatus.Finished,
Type = DownloadStationTaskType.NZB.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
},
}
};
_seeding = new DownloadStationTask()
{
Id = "id2",
Size = 1000,
Status = DownloadStationTaskStatus.Seeding,
Type = DownloadStationTaskType.NZB.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "1000"},
{ "speed_download", "0" }
}
}
};
_downloading = new DownloadStationTask()
{
Id = "id3",
Size = 1000,
Status = DownloadStationTaskStatus.Downloading,
Type = DownloadStationTaskType.NZB.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "100"},
{ "speed_download", "50" }
}
}
};
_failed = new DownloadStationTask()
{
Id = "id4",
Size = 1000,
Status = DownloadStationTaskStatus.Error,
Type = DownloadStationTaskType.NZB.ToString(),
Username = "admin",
Title = "title",
Additional = new DownloadStationTaskAdditional
{
Detail = new Dictionary<string, string>
{
{ "destination","shared/folder" },
{ "uri", FileNameBuilder.CleanFileName(_remoteEpisode.Release.Title) + ".nzb" }
},
Transfer = new Dictionary<string, string>
{
{ "size_downloaded", "10"},
{ "speed_download", "0" }
}
}
};
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0]));
_downloadStationConfigItems = new Dictionary<string, object>
{
{ "default_destination", _defaultDestination },
};
Mocker.GetMock<IDownloadStationInfoProxy>()
.Setup(v => v.GetConfig(It.IsAny<DownloadStationSettings>()))
.Returns(_downloadStationConfigItems);
}
protected void GivenSharedFolder()
{
Mocker.GetMock<ISharedFolderResolver>()
.Setup(s => s.RemapToFullPath(It.IsAny<OsPath>(), It.IsAny<DownloadStationSettings>(), It.IsAny<string>()))
.Returns<OsPath, DownloadStationSettings, string>((path, setttings, serial) => _physicalPath);
}
protected void GivenSerialNumber()
{
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(It.IsAny<DownloadStationSettings>()))
.Returns(_serialNumber);
}
protected void GivenTvCategory()
{
_settings.TvCategory = _category;
}
protected void GivenTvDirectory()
{
_settings.TvDirectory = _tvDirectory;
}
protected virtual void GivenTasks(List<DownloadStationTask> nzbs)
{
if (nzbs == null)
{
nzbs = new List<DownloadStationTask>();
}
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.GetTasks(It.IsAny<DownloadStationSettings>()))
.Returns(nzbs);
}
protected void PrepareClientToReturnQueuedItem()
{
GivenTasks(new List<DownloadStationTask>
{
_queued
});
}
protected void GivenSuccessfulDownload()
{/*
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[1000]));
*/
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(s => s.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DownloadStationSettings>()))
.Callback(PrepareClientToReturnQueuedItem);
}
protected void GivenAllKindOfTasks()
{
var tasks = new List<DownloadStationTask>() { _queued, _completed, _failed, _downloading, _seeding };
Mocker.GetMock<IDownloadStationTaskProxy>()
.Setup(d => d.GetTasks(_settings))
.Returns(tasks);
}
[Test]
public void Download_with_TvDirectory_should_force_directory()
{
GivenSerialNumber();
GivenTvDirectory();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), _tvDirectory, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void Download_with_category_should_force_directory()
{
GivenSerialNumber();
GivenTvCategory();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), $"{_defaultDestination}/{_category}", It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void Download_without_TvDirectory_and_Category_should_use_default()
{
GivenSerialNumber();
GivenSuccessfulDownload();
var remoteEpisode = CreateRemoteEpisode();
var id = Subject.Download(remoteEpisode);
id.Should().NotBeNullOrEmpty();
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromData(It.IsAny<byte[]>(), It.IsAny<string>(), null, It.IsAny<DownloadStationSettings>()), Times.Once());
}
[Test]
public void GetItems_should_return_empty_list_if_no_tasks_available()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>());
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_return_ignore_tasks_of_unknown_type()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask> { _completed });
_completed.Type = "ipfs";
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_ignore_downloads_in_wrong_folder()
{
_settings.TvDirectory = @"/shared/folder/sub";
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask> { _completed });
Subject.GetItems().Should().BeEmpty();
}
[Test]
public void GetItems_should_throw_if_shared_folder_resolve_fails()
{
Mocker.GetMock<ISharedFolderResolver>()
.Setup(s => s.RemapToFullPath(It.IsAny<OsPath>(), It.IsAny<DownloadStationSettings>(), It.IsAny<string>()))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
GivenSerialNumber();
GivenAllKindOfTasks();
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetItems());
ExceptionVerification.ExpectedErrors(0);
}
[Test]
public void GetItems_should_throw_if_serial_number_unavailable()
{
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
GivenSharedFolder();
GivenAllKindOfTasks();
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.GetItems());
ExceptionVerification.ExpectedErrors(0);
}
[Test]
public void Download_should_throw_and_not_add_task_if_cannot_get_serial_number()
{
var remoteEpisode = CreateRemoteEpisode();
Mocker.GetMock<ISerialNumberProvider>()
.Setup(s => s.GetSerialNumber(_settings))
.Throws(new ApplicationException("Some unknown exception, HttpException or DownloadClientException"));
Assert.Throws(Is.InstanceOf<Exception>(), () => Subject.Download(remoteEpisode));
Mocker.GetMock<IDownloadStationTaskProxy>()
.Verify(v => v.AddTaskFromUrl(It.IsAny<string>(), null, _settings), Times.Never());
}
[Test]
public void GetItems_should_not_map_outputpath_for_queued_or_downloading_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>
{
_queued, _downloading
});
var items = Subject.GetItems();
items.Should().HaveCount(2);
items.Should().OnlyContain(v => v.OutputPath.IsEmpty);
}
[Test]
public void GetItems_should_map_outputpath_for_completed_or_failed_tasks()
{
GivenSerialNumber();
GivenSharedFolder();
GivenTasks(new List<DownloadStationTask>
{
_completed, _failed, _seeding
});
var items = Subject.GetItems();
items.Should().HaveCount(3);
items.Should().OnlyContain(v => !v.OutputPath.IsEmpty);
}
[TestCase(DownloadStationTaskStatus.Downloading, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Error, DownloadItemStatus.Failed)]
[TestCase(DownloadStationTaskStatus.Extracting, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Finished, DownloadItemStatus.Completed)]
[TestCase(DownloadStationTaskStatus.Finishing, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.HashChecking, DownloadItemStatus.Downloading)]
[TestCase(DownloadStationTaskStatus.Paused, DownloadItemStatus.Paused)]
[TestCase(DownloadStationTaskStatus.Waiting, DownloadItemStatus.Queued)]
public void GetItems_should_return_item_as_downloadItemStatus(DownloadStationTaskStatus apiStatus, DownloadItemStatus expectedItemStatus)
{
GivenSerialNumber();
GivenSharedFolder();
_queued.Status = apiStatus;
GivenTasks(new List<DownloadStationTask>() { _queued });
var items = Subject.GetItems();
items.Should().HaveCount(1);
items.First().Status.Should().Be(expectedItemStatus);
}
}
}

View File

@@ -190,6 +190,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.HadoukenTests
PrepareClientToReturnCompletedItem();
var item = Subject.GetItems().Single();
VerifyCompleted(item);
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
@@ -298,7 +301,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.HadoukenTests
.Returns("hash");
var result = Subject.Download(remoteEpisode);
Assert.IsFalse(result.Any(c => char.IsLower(c)));
}

View File

@@ -103,7 +103,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
public void queued_item_should_have_required_properties()
{
GivenQueue(_queued);
var result = Subject.GetItems().Single();
VerifyQueued(result);
@@ -139,6 +139,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbVortexTests
var result = Subject.GetItems().Single();
VerifyCompleted(result);
result.CanBeRemoved.Should().BeTrue();
result.CanMoveFiles.Should().BeTrue();
}
[Test]

View File

@@ -92,14 +92,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
protected void GivenFailedDownload()
{
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<NzbgetSettings>()))
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<NzbgetSettings>()))
.Returns((string)null);
}
protected void GivenSuccessfulDownload()
{
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<NzbgetSettings>()))
.Setup(s => s.DownloadNzb(It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<NzbgetSettings>()))
.Returns(Guid.NewGuid().ToString().Replace("-", ""));
}
@@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
GivenQueue(_queued);
GivenHistory(null);
var result = Subject.GetItems().Single();
VerifyQueued(result);
@@ -204,6 +204,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
var result = Subject.GetItems().Single();
VerifyCompleted(result);
result.CanBeRemoved.Should().BeTrue();
result.CanMoveFiles.Should().BeTrue();
}
[Test]

View File

@@ -311,7 +311,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
}
[Test]
public void should_be_read_only_if_max_ratio_not_reached()
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_not_reached()
{
GivenMaxRatio(1.0f);
@@ -330,11 +330,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
GivenTorrents(new List<QBittorrentTorrent> { torrent });
var item = Subject.GetItems().Single();
item.IsReadOnly.Should().BeTrue();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_be_read_only_if_max_ratio_reached_and_not_paused()
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_paused()
{
GivenMaxRatio(1.0f);
@@ -353,11 +354,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
GivenTorrents(new List<QBittorrentTorrent> { torrent });
var item = Subject.GetItems().Single();
item.IsReadOnly.Should().BeTrue();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_be_read_only_if_max_ratio_is_not_set()
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_is_not_set()
{
GivenMaxRatio(1.0f, false);
@@ -376,11 +378,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
GivenTorrents(new List<QBittorrentTorrent> { torrent });
var item = Subject.GetItems().Single();
item.IsReadOnly.Should().BeTrue();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_not_be_read_only_if_max_ratio_reached_and_paused()
public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_and_paused()
{
GivenMaxRatio(1.0f);
@@ -399,7 +402,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
GivenTorrents(new List<QBittorrentTorrent> { torrent });
var item = Subject.GetItems().Single();
item.IsReadOnly.Should().BeFalse();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]

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<RTorrentSettings>()))
.Setup(s => s.AddTorrentFromUrl(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
.Callback(PrepareClientToReturnCompletedItem);
Mocker.GetMock<IRTorrentProxy>()
.Setup(s => s.AddTorrentFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<RTorrentSettings>()))
.Setup(s => s.AddTorrentFromFile(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<string>(), It.IsAny<RTorrentPriority>(), It.IsAny<string>(), It.IsAny<RTorrentSettings>()))
.Callback(PrepareClientToReturnCompletedItem);

View File

@@ -23,6 +23,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
private SabnzbdHistory _failed;
private SabnzbdHistory _completed;
private SabnzbdConfig _config;
private SabnzbdFullStatus _fullStatus;
[SetUp]
public void Setup()
@@ -65,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
Status = SabnzbdDownloadStatus.Failed,
Size = 1000,
Category = "tv",
Category = "tv",
Id = "sabnzbd_nzb12345",
Title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"
}
@@ -80,7 +81,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
Status = SabnzbdDownloadStatus.Completed,
Size = 1000,
Category = "tv",
Category = "tv",
Id = "sabnzbd_nzb12345",
Title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
Storage = "/remote/mount/vv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"
@@ -100,9 +101,29 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
}
};
Mocker.GetMock<ISabnzbdProxy>()
.Setup(v => v.GetVersion(It.IsAny<SabnzbdSettings>()))
.Returns("1.2.3");
Mocker.GetMock<ISabnzbdProxy>()
.Setup(s => s.GetConfig(It.IsAny<SabnzbdSettings>()))
.Returns(_config);
_fullStatus = new SabnzbdFullStatus
{
CompleteDir = @"Y:\nzbget\root\complete".AsOsAgnostic()
};
Mocker.GetMock<ISabnzbdProxy>()
.Setup(s => s.GetFullStatus(It.IsAny<SabnzbdSettings>()))
.Returns(_fullStatus);
}
protected void GivenVersion(string version)
{
Mocker.GetMock<ISabnzbdProxy>()
.Setup(s => s.GetVersion(It.IsAny<SabnzbdSettings>()))
.Returns(version);
}
protected void GivenFailedDownload()
@@ -166,7 +187,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
GivenQueue(_queued);
GivenHistory(null);
var result = Subject.GetItems().Single();
VerifyQueued(result);
@@ -218,6 +239,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
var result = Subject.GetItems().Single();
VerifyCompleted(result);
result.CanBeRemoved.Should().BeTrue();
result.CanMoveFiles.Should().BeTrue();
}
[Test]
@@ -386,23 +410,46 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputPath.Should().Be(@"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic());
}
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed/vv")]
public void should_return_status_with_outputdir(string rootFolder, string completeDir, string categoryDir, string expectedDir)
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_lt_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{
_fullStatus.CompleteDir = null;
_queued.DefaultRootFolder = rootFolder;
_config.Misc.complete_dir = completeDir;
_config.Categories.First().Dir = categoryDir;
GivenVersion("1.2.1");
GivenQueue(null);
var result = Subject.GetStatus();
result.IsLocalhost.Should().BeTrue();
result.OutputRootFolders.Should().NotBeNull();
result.OutputRootFolders.First().Should().Be(expectedDir);
result.OutputRootFolders.First().Should().Be(fullCategoryDir);
}
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_gte_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{
_fullStatus.CompleteDir = fullCompleteDir;
_queued.DefaultRootFolder = null;
_config.Misc.complete_dir = completeDir;
_config.Categories.First().Dir = categoryDir;
GivenVersion("2.0.0beta1");
GivenQueue(null);
var result = Subject.GetStatus();
result.IsLocalhost.Should().BeTrue();
result.OutputRootFolders.Should().NotBeNull();
result.OutputRootFolders.First().Should().Be(fullCategoryDir);
}
[Test]
@@ -450,5 +497,73 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.IsValid.Should().BeTrue();
result.HasWarnings.Should().BeTrue();
}
[Test]
public void should_test_success_if_tv_sorting_disabled()
{
_config.Misc.enable_tv_sorting = false;
_config.Misc.tv_categories = null;
var result = new NzbDroneValidationResult(Subject.Test());
result.IsValid.Should().BeTrue();
}
[Test]
public void should_test_failed_if_tv_sorting_null()
{
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = null;
var result = new NzbDroneValidationResult(Subject.Test());
result.IsValid.Should().BeFalse();
}
[Test]
public void should_test_failed_if_tv_sorting_empty()
{
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new string[0];
var result = new NzbDroneValidationResult(Subject.Test());
result.IsValid.Should().BeFalse();
}
[Test]
public void should_test_success_if_tv_sorting_contains_different_category()
{
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "tv-custom" };
var result = new NzbDroneValidationResult(Subject.Test());
result.IsValid.Should().BeTrue();
}
[Test]
public void should_test_failed_if_tv_sorting_contains_category()
{
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "tv" };
var result = new NzbDroneValidationResult(Subject.Test());
result.IsValid.Should().BeFalse();
}
[Test]
public void should_test_failed_if_tv_sorting_default_category()
{
Subject.Definition.Settings.As<SabnzbdSettings>().TvCategory = null;
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "Default" };
var result = new NzbDroneValidationResult(Subject.Test());
result.IsValid.Should().BeFalse();
}
}
}

View File

@@ -41,6 +41,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
PrepareClientToReturnCompletedItem();
var item = Subject.GetItems().Single();
VerifyCompleted(item);
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
@@ -172,13 +175,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
item.Status.Should().Be(expectedItemStatus);
}
[TestCase(TransmissionTorrentStatus.Stopped, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.CheckWait, DownloadItemStatus.Downloading, true)]
[TestCase(TransmissionTorrentStatus.Check, DownloadItemStatus.Downloading, true)]
[TestCase(TransmissionTorrentStatus.Queued, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.SeedingWait, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.Seeding, DownloadItemStatus.Completed, true)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(TransmissionTorrentStatus apiStatus, DownloadItemStatus expectedItemStatus, bool expectedReadOnly)
[TestCase(TransmissionTorrentStatus.Stopped, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.CheckWait, DownloadItemStatus.Downloading, false)]
[TestCase(TransmissionTorrentStatus.Check, DownloadItemStatus.Downloading, false)]
[TestCase(TransmissionTorrentStatus.Queued, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.SeedingWait, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.Seeding, DownloadItemStatus.Completed, false)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(TransmissionTorrentStatus apiStatus, DownloadItemStatus expectedItemStatus, bool expectedValue)
{
_completed.Status = apiStatus;
@@ -187,7 +190,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
var item = Subject.GetItems().Single();
item.Status.Should().Be(expectedItemStatus);
item.IsReadOnly.Should().Be(expectedReadOnly);
item.CanBeRemoved.Should().Be(expectedValue);
item.CanMoveFiles.Should().Be(expectedValue);
}
[Test]

View File

@@ -222,6 +222,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
PrepareClientToReturnCompletedItem();
var item = Subject.GetItems().Single();
VerifyCompleted(item);
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
@@ -292,12 +295,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
item.Status.Should().Be(expectedItemStatus);
}
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checking, DownloadItemStatus.Queued, false)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked, DownloadItemStatus.Completed, false)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked | UTorrentTorrentStatus.Queued, DownloadItemStatus.Completed, true)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked | UTorrentTorrentStatus.Started, DownloadItemStatus.Completed, true)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked | UTorrentTorrentStatus.Queued | UTorrentTorrentStatus.Paused, DownloadItemStatus.Completed, true)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(UTorrentTorrentStatus apiStatus, DownloadItemStatus expectedItemStatus, bool expectedReadOnly)
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checking, DownloadItemStatus.Queued, true)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked, DownloadItemStatus.Completed, true)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked | UTorrentTorrentStatus.Queued, DownloadItemStatus.Completed, false)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked | UTorrentTorrentStatus.Started, DownloadItemStatus.Completed, false)]
[TestCase(UTorrentTorrentStatus.Loaded | UTorrentTorrentStatus.Checked | UTorrentTorrentStatus.Queued | UTorrentTorrentStatus.Paused, DownloadItemStatus.Completed, false)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(UTorrentTorrentStatus apiStatus, DownloadItemStatus expectedItemStatus, bool expectedValue)
{
_completed.Status = apiStatus;
@@ -306,7 +309,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
var item = Subject.GetItems().Single();
item.Status.Should().Be(expectedItemStatus);
item.IsReadOnly.Should().Be(expectedReadOnly);
item.CanBeRemoved.Should().Be(expectedValue);
item.CanMoveFiles.Should().Be(expectedValue);
}
[Test]

View File

@@ -43,6 +43,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
PrepareClientToReturnCompletedItem();
var item = Subject.GetItems().Single();
VerifyCompleted(item);
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
@@ -174,13 +177,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
item.Status.Should().Be(expectedItemStatus);
}
[TestCase(TransmissionTorrentStatus.Stopped, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.CheckWait, DownloadItemStatus.Downloading, true)]
[TestCase(TransmissionTorrentStatus.Check, DownloadItemStatus.Downloading, true)]
[TestCase(TransmissionTorrentStatus.Queued, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.SeedingWait, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.Seeding, DownloadItemStatus.Completed, true)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(TransmissionTorrentStatus apiStatus, DownloadItemStatus expectedItemStatus, bool expectedReadOnly)
[TestCase(TransmissionTorrentStatus.Stopped, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.CheckWait, DownloadItemStatus.Downloading, false)]
[TestCase(TransmissionTorrentStatus.Check, DownloadItemStatus.Downloading, false)]
[TestCase(TransmissionTorrentStatus.Queued, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.SeedingWait, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.Seeding, DownloadItemStatus.Completed, false)]
public void GetItems_should_return_completed_item_as_downloadItemStatus(TransmissionTorrentStatus apiStatus, DownloadItemStatus expectedItemStatus, bool expectedValue)
{
_completed.Status = apiStatus;
@@ -189,7 +192,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
var item = Subject.GetItems().Single();
item.Status.Should().Be(expectedItemStatus);
item.IsReadOnly.Should().Be(expectedReadOnly);
item.CanBeRemoved.Should().Be(expectedValue);
item.CanMoveFiles.Should().Be(expectedValue);
}
[Test]
@@ -312,4 +316,4 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
}
}
}
}

View File

@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:torrent="http://xmlns.ezrss.it/0.1/">
<channel>
<title>tv torrents RSS feed - KickassTorrents</title>
<link>http://kickass.to/</link>
<description>tv torrents RSS feed</description>
<item>
<title>Doctor Stranger.E03.140512.HDTV.H264.720p-iPOP.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/doctor-stranger-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100648.html</link>
<guid>http://kickass.to/doctor-stranger-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100648.html</guid>
<pubDate>Mon, 12 May 2014 16:16:49 +0000</pubDate>
<torrent:contentLength>1205364736</torrent:contentLength>
<torrent:infoHash>208C4F7866612CC88BFEBC7C496FA72C2368D1C0</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:208C4F7866612CC88BFEBC7C496FA72C2368D1C0&dn=doctor+stranger+e03+140512+hdtv+h264+720p+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>206</torrent:seeds>
<torrent:peers>311</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>doctor.stranger.e03.140512.hdtv.h264.720p.ipop.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/208C4F7866612CC88BFEBC7C496FA72C2368D1C0.torrent?title=%5Bkickass.to%5Ddoctor.stranger.e03.140512.hdtv.h264.720p.ipop.avi.ctrg" length="1205364736" type="application/x-bittorrent" />
</item>
<item>
<title>Triangle.E03.140512.HDTV.XViD-iPOP.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/triangle-e03-140512-hdtv-xvid-ipop-avi-ctrg-t9100647.html</link>
<guid>http://kickass.to/triangle-e03-140512-hdtv-xvid-ipop-avi-ctrg-t9100647.html</guid>
<pubDate>Mon, 12 May 2014 16:16:31 +0000</pubDate>
<torrent:contentLength>677543936</torrent:contentLength>
<torrent:infoHash>BF22A53C9889A7D325F2A3D904E566B7DF4074EB</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:BF22A53C9889A7D325F2A3D904E566B7DF4074EB&dn=triangle+e03+140512+hdtv+xvid+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>242</torrent:seeds>
<torrent:peers>374</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>triangle.e03.140512.hdtv.xvid.ipop.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/BF22A53C9889A7D325F2A3D904E566B7DF4074EB.torrent?title=%5Bkickass.to%5Dtriangle.e03.140512.hdtv.xvid.ipop.avi.ctrg" length="677543936" type="application/x-bittorrent" />
</item>
<item>
<title>Triangle.E03.140512.HDTV.H264.720p-iPOP.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/triangle-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100646.html</link>
<guid>http://kickass.to/triangle-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100646.html</guid>
<pubDate>Mon, 12 May 2014 16:16:10 +0000</pubDate>
<torrent:contentLength>1196869632</torrent:contentLength>
<torrent:infoHash>8427BFB8884B8228364EBB9B3EA7D8B77E03A7BC</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:8427BFB8884B8228364EBB9B3EA7D8B77E03A7BC&dn=triangle+e03+140512+hdtv+h264+720p+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>177</torrent:seeds>
<torrent:peers>268</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>triangle.e03.140512.hdtv.h264.720p.ipop.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/8427BFB8884B8228364EBB9B3EA7D8B77E03A7BC.torrent?title=%5Bkickass.to%5Dtriangle.e03.140512.hdtv.h264.720p.ipop.avi.ctrg" length="1196869632" type="application/x-bittorrent" />
</item>
<item>
<title>Triangle.E03.140512.HDTV.X264.720p-BarosG_.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/triangle-e03-140512-hdtv-x264-720p-barosg-avi-ctrg-t9100644.html</link>
<guid>http://kickass.to/triangle-e03-140512-hdtv-x264-720p-barosg-avi-ctrg-t9100644.html</guid>
<pubDate>Mon, 12 May 2014 16:15:52 +0000</pubDate>
<torrent:contentLength>1418906266</torrent:contentLength>
<torrent:infoHash>5556B773893DB55287ECEC581E850B853163DB11</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:5556B773893DB55287ECEC581E850B853163DB11&dn=triangle+e03+140512+hdtv+x264+720p+barosg+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>522</torrent:seeds>
<torrent:peers>785</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>triangle.e03.140512.hdtv.x264.720p.barosg.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/5556B773893DB55287ECEC581E850B853163DB11.torrent?title=%5Bkickass.to%5Dtriangle.e03.140512.hdtv.x264.720p.barosg.avi.ctrg" length="1418906266" type="application/x-bittorrent" />
</item>
<item>
<title>Battlestar Galactica 1978 Dvd3 e09 e10 e11 e12 [NL] [FR] [ENG] Sub</title>
<description>
<![CDATA[In een afgelegen zonnestelsel leeft een mensenras op twaalf koloniewerelden. Ze zijn al eeuwen in oorlog met de Cylons, gevechtsrobots die ooit werden gemaakt door een allang verdwenen buitenaards reptielachtig ras. Met de hulp van de menselijke verrader Baltar zijn de Cylons erin geslaagd de mensheid vrijwel uit te roeien. Slechts een oorlogsschip kan aan de vernietiging ontkomen: de Battlestar Galactica van commandant Adama.
Met een vloot burgerschepen vol vluchtelingen vlucht de Galactica voor de Cylons. Adama besluit op zoek te gaan naar de legendarische 13e en laatste kolonie, genaamd Aarde. Tijdens de lange en gevaarlijke reis worden ze voortdurend bedreigd door de achtervolgende Cylons en andere gevaren.]]>
</description>
<category>TV</category>
<author>http://kickass.to/user/hendriknl/</author>
<link>http://kickass.to/battlestar-galactica-1978-dvd3-e09-e10-e11-e12-nl-fr-eng-sub-t9100642.html</link>
<guid>http://kickass.to/battlestar-galactica-1978-dvd3-e09-e10-e11-e12-nl-fr-eng-sub-t9100642.html</guid>
<pubDate>Mon, 12 May 2014 16:15:46 +0000</pubDate>
<torrent:contentLength>4680841216</torrent:contentLength>
<torrent:infoHash>3D293CAFEDAC595F6E55F9C284DD76862FE254F6</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:3D293CAFEDAC595F6E55F9C284DD76862FE254F6&dn=battlestar+galactica+1978+dvd3+e09+e10+e11+e12+nl+fr+eng+sub&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>2</torrent:seeds>
<torrent:peers>5</torrent:peers>
<torrent:verified>0</torrent:verified>
<torrent:fileName>battlestar.galactica.1978.dvd3.e09.e10.e11.e12.nl.fr.eng.sub.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/3D293CAFEDAC595F6E55F9C284DD76862FE254F6.torrent?title=%5Bkickass.to%5Dbattlestar.galactica.1978.dvd3.e09.e10.e11.e12.nl.fr.eng.sub" length="4680841216" type="application/x-bittorrent" />
</item>
</channel>
</rss>

View File

@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:torrent="http://xmlns.ezrss.it/0.1/">
<channel>
<title>tv torrents RSS feed - KickassTorrents</title>
<link>http://kickass.to/</link>
<description>tv torrents RSS feed</description>
<item>
<title>Doctor Strang&eacute;r.E03.140512.HDTV.H264.720p-iPOP.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/doctor-stranger-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100648.html</link>
<guid>http://kickass.to/doctor-stranger-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100648.html</guid>
<pubDate>Mon, 12 May 2014 16:16:49 +0000</pubDate>
<torrent:contentLength>1205364736</torrent:contentLength>
<torrent:infoHash>208C4F7866612CC88BFEBC7C496FA72C2368D1C0</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:208C4F7866612CC88BFEBC7C496FA72C2368D1C0&dn=doctor+stranger+e03+140512+hdtv+h264+720p+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>206</torrent:seeds>
<torrent:peers>311</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>doctor.stranger.e03.140512.hdtv.h264.720p.ipop.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/208C4F7866612CC88BFEBC7C496FA72C2368D1C0.torrent?title=%5Bkickass.to%5Ddoctor.stranger.e03.140512.hdtv.h264.720p.ipop.avi.ctrg" length="1205364736" type="application/x-bittorrent" />
</item>
<item>
<title>Triangle.E03.140512.HDTV.XViD-iPOP.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/triangle-e03-140512-hdtv-xvid-ipop-avi-ctrg-t9100647.html</link>
<guid>http://kickass.to/triangle-e03-140512-hdtv-xvid-ipop-avi-ctrg-t9100647.html</guid>
<pubDate>Mon, 12 May 2014 16:16:31 +0000</pubDate>
<torrent:contentLength>677543936</torrent:contentLength>
<torrent:infoHash>BF22A53C9889A7D325F2A3D904E566B7DF4074EB</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:BF22A53C9889A7D325F2A3D904E566B7DF4074EB&dn=triangle+e03+140512+hdtv+xvid+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>242</torrent:seeds>
<torrent:peers>374</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>triangle.e03.140512.hdtv.xvid.ipop.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/BF22A53C9889A7D325F2A3D904E566B7DF4074EB.torrent?title=%5Bkickass.to%5Dtriangle.e03.140512.hdtv.xvid.ipop.avi.ctrg" length="677543936" type="application/x-bittorrent" />
</item>
<item>
<title>Triangle.E03.140512.HDTV.H264.720p-iPOP.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/triangle-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100646.html</link>
<guid>http://kickass.to/triangle-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100646.html</guid>
<pubDate>Mon, 12 May 2014 16:16:10 +0000</pubDate>
<torrent:contentLength>1196869632</torrent:contentLength>
<torrent:infoHash>8427BFB8884B8228364EBB9B3EA7D8B77E03A7BC</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:8427BFB8884B8228364EBB9B3EA7D8B77E03A7BC&dn=triangle+e03+140512+hdtv+h264+720p+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>177</torrent:seeds>
<torrent:peers>268</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>triangle.e03.140512.hdtv.h264.720p.ipop.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/8427BFB8884B8228364EBB9B3EA7D8B77E03A7BC.torrent?title=%5Bkickass.to%5Dtriangle.e03.140512.hdtv.h264.720p.ipop.avi.ctrg" length="1196869632" type="application/x-bittorrent" />
</item>
<item>
<title>Triangle.E03.140512.HDTV.X264.720p-BarosG_.avi [CTRG]</title>
<category>TV</category>
<author>http://kickass.to/user/2NE1/</author>
<link>http://kickass.to/triangle-e03-140512-hdtv-x264-720p-barosg-avi-ctrg-t9100644.html</link>
<guid>http://kickass.to/triangle-e03-140512-hdtv-x264-720p-barosg-avi-ctrg-t9100644.html</guid>
<pubDate>Mon, 12 May 2014 16:15:52 +0000</pubDate>
<torrent:contentLength>1418906266</torrent:contentLength>
<torrent:infoHash>5556B773893DB55287ECEC581E850B853163DB11</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:5556B773893DB55287ECEC581E850B853163DB11&dn=triangle+e03+140512+hdtv+x264+720p+barosg+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>522</torrent:seeds>
<torrent:peers>785</torrent:peers>
<torrent:verified>1</torrent:verified>
<torrent:fileName>triangle.e03.140512.hdtv.x264.720p.barosg.avi.ctrg.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/5556B773893DB55287ECEC581E850B853163DB11.torrent?title=%5Bkickass.to%5Dtriangle.e03.140512.hdtv.x264.720p.barosg.avi.ctrg" length="1418906266" type="application/x-bittorrent" />
</item>
<item>
<title>Battlestar Galactica 1978 Dvd3 e09 e10 e11 e12 [NL] [FR] [ENG] Sub</title>
<description>
<![CDATA[In een afgelegen zonnestelsel leeft een mensenras op twaalf koloniewerelden. Ze zijn al eeuwen in oorlog met de Cylons, gevechtsrobots die ooit werden gemaakt door een allang verdwenen buitenaards reptielachtig ras. Met de hulp van de menselijke verrader Baltar zijn de Cylons erin geslaagd de mensheid vrijwel uit te roeien. Slechts een oorlogsschip kan aan de vernietiging ontkomen: de Battlestar Galactica van commandant Adama.
Met een vloot burgerschepen vol vluchtelingen vlucht de Galactica voor de Cylons. Adama besluit op zoek te gaan naar de legendarische 13e en laatste kolonie, genaamd Aarde. Tijdens de lange en gevaarlijke reis worden ze voortdurend bedreigd door de achtervolgende Cylons en andere gevaren.]]>
</description>
<category>TV</category>
<author>http://kickass.to/user/hendriknl/</author>
<link>http://kickass.to/battlestar-galactica-1978-dvd3-e09-e10-e11-e12-nl-fr-eng-sub-t9100642.html</link>
<guid>http://kickass.to/battlestar-galactica-1978-dvd3-e09-e10-e11-e12-nl-fr-eng-sub-t9100642.html</guid>
<pubDate>Mon, 12 May 2014 16:15:46 +0000</pubDate>
<torrent:contentLength>4680841216</torrent:contentLength>
<torrent:infoHash>3D293CAFEDAC595F6E55F9C284DD76862FE254F6</torrent:infoHash>
<torrent:magnetURI><![CDATA[magnet:?xt=urn:btih:3D293CAFEDAC595F6E55F9C284DD76862FE254F6&dn=battlestar+galactica+1978+dvd3+e09+e10+e11+e12+nl+fr+eng+sub&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce]]></torrent:magnetURI>
<torrent:seeds>2</torrent:seeds>
<torrent:peers>5</torrent:peers>
<torrent:verified>0</torrent:verified>
<torrent:fileName>battlestar.galactica.1978.dvd3.e09.e10.e11.e12.nl.fr.eng.sub.torrent</torrent:fileName>
<enclosure url="http://torcache.net/torrent/3D293CAFEDAC595F6E55F9C284DD76862FE254F6.torrent?title=%5Bkickass.to%5Dbattlestar.galactica.1978.dvd3.e09.e10.e11.e12.nl.fr.eng.sub" length="4680841216" type="application/x-bittorrent" />
</item>
</channel>
</rss>

View File

@@ -0,0 +1,281 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
<meta xmlns="http://pipes.yahoo.com" name="pipes" content="noprocess" />
<title>TV :: AlphaRatio</title>
<link>https://alpharatio.cc/</link>
<description>Personal RSS feed: TV</description>
<language>en-us</language>
<lastBuildDate>Tue, 29 Nov 2016 11:01:28 +0000</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Gazelle Feed Class</generator>
<item>
<title><![CDATA[TvHD 465989 465960 Good.Behavior.S01E03.PROPER.720p.HDTV.x264-KILLERS]]></title>
<description>
<![CDATA[MB <br />
@@@@: : <br />
:7 :::.7:@.:u7:.X5LF <br />
.LFq2 .B@B@B@B@B@B@B@ <br />
.. i@r rB@B@B@B@B@B@B@@@: <br />
: :B@B@B@B@: X@@@@@B@B@B@B@B@B@B@J .u@B. <br />
:.YkuB@B@B@BM. @B@B@B@B@B@@@B@B@B@r 2B@B@B@B@i <br />
@@@B@r@@@B@B: B@B@B@B@B@@@B@B@B@B@ i@B@B@B@BrO@@@@@ <br />
@@@@B@B@BB, r:@B@B@@@B@@@B@q@@@BM @L:B.B, @@B@B@B@BO@@@@B@B@B <br />
jB@B@B@B@N. 7 B@@@@@B@B@O 8B@. @F B@B@B@@@O@B@B@B@@@@@B. <br />
i@B@B@B@: 7 @B@B@B@B@ B: B: i@B@B@B@BNB8B7 .B@@ <br />
@B@B@. 1G @B@B@B@ @ , @B@:i @u @: 0EB@ <br />
;ir , U@B@B .@ B@B L B@B <br />
7 B@B@ q@Bv:@BP @B@ <br />
i@Bu @ ,S@ @@ B@@@B@B@. BkU@B@ 5Ui @Y@B <br />
@@B@v B :@iB B@@@B@B@M@ @B@@@B@BB @@7i iU 5i2vB@k B@ <br />
@B@B@B7 i @ @B@B@B@B@B@B5 i@B@@@B@ r @ <br />
@B@B@B@. @ B@B@B@B@B@B@B@. MB @Bu . U @Bi <br />
k@P @@@OBi .@ @B@B@B@B@B@B@B. @MBB@@ @F @ 7B@B <br />
@B @B@@@B@ 0B@B@B@B@B@B@B@B@ B@B@B@B@F B@B@B. B@B <br />
B @B@B@B B: B@B@B@B@@@B@@@BM B@B@B@B@B@: @B@;:B@@@: F@B <br />
@. B@@@B@ @Bu i. MX J B@B@B@ @B. @B@B@B@@ B@B@F Si k@@ B@BN <br />
@@ @B@B@B@B@B B @B@BOr: .i0F7@B: B@B@ E@ @B@B@r@ B@B@B. @B@B@B5 <br />
B@B@B@@@B@B@B: @B@B@B@Z: B@B@B@B@B@B@@@B, L@ @B@ B@B@B@B@B@B@B, <br />
:@B@B@B@B@B@B@: Y@B@@@@@B@B@B@: 7B@@@0 :@ L@ ,@B@B@B@B@B@B@B@. <br />
JB@B@B@B@B@B@B@ U@B@@J, @U.@@B@B@B B@F i@ PB @B@B@B@B@BG.@B@B@B, <br />
r@B@B@B@B@B@B@B ; @B@B@ :. @ @J r@ G@ @@: .Z@@7 B@@@@@B@B@B@F <br />
,B@B@B@B@B@B@B@B5 @B@@@ j@B5E@BXB@BvO rB OB B@ B@@@r B@B@B@B@B@B@B@B. <br />
@B@B@B@B@B@@@B@i @@ .uO0 :v. @ @B@B @@@ L: ,@ .@ Z@ iB B@B @B@B@@@BNB@ :2@B@B@B@@@B@B <br />
:@@B@B@B@B@@@B@B..@@@B@B@@. :YY B@@@: B, B .: u@ .@B@B r@ OB i@B@B@@@B@B <br />
UB@B@B@B@B@@@B@B@B@B@B LJ, @B@B. @. @ Y @BP .rUB@B@B@B@Z7, B@B@B@B@B@ <br />
,@B@@@B@B@B@B@B@@@ i17. @B@B@v O, B 1B@B@B@B@@@B@@@B@B@B@B@B@B@B@BiB@Bv<br />
:B@B@B@B@B@B@B@2@B B@B@B@ k. .@ M@@BOB@B@B@B@B@B@B@B@B@B@B@B@B@P @@B<br />
i@B@B@@@B@B@B@B M@B .7 @B@B@r B. 7B @ YB@B@B@B@B@B@B@B@B@B@B@B@B@B@B@B@B@@@<br />
u@@B@B@B@@@B@B@ B@B@ 2U8. 5B@@E @, r@ M B@B@B@B@B@B@B@B@B@@@B@B@B@B@@@B@@@@@B<br />
q@B@B@B@@@B@B@B. @@@i2 @JX :@B@ BY rB @ G@@B@B@B@B@B@B@B@B@B@B@B@B@B@B@B@B@B@<br />
BB@B@B@B@B@B@Bi . B@@: @B @ @B@B@B@B@B@B@B@B@B@B@B@@@@@B@B@B@j<br />
O@B@B@B@B@B@B@@@ u@B@@ Bu B @@B@B@B@BB8 0B@B@B <br />
SB@B@B@B@B@B@B@B@B @@B@@@B @ .BS r @@@B@ <br />
.@B@B@B@B@B@B@B@B@ B@B@@@B@Br XB@Br 7B u .vB B: B@B@B@B <br />
@@@@B@B@B@B@B@B@B@B@B .@B@B@B@B@@M i..@. i i i P @,jB @@B <br />
@B@B@B@B@B@B@B@B@B@B@B@i @N@@@B@@@B@B@B @ B@E <br />
@B@B@B@@@B@B@B@B@B@B@B@B @ : @@B@B@@@Mi B . @@ <br />
F@B@@@B@B@B@B@B@@@B@B@B@,@ M @.:v X i B :BM <br />
i@B@B@B@B@@@B@B@B@@@@@B@B L ,r , ; B@. @B@, <br />
,M@B@B @B@B@B@B@@@B@B@B@ rL B j :jr@B@@r @B@B@B <br />
@B@B@B@B@B@B@B@B .: . .@ : , @@@@B@@ <br />
,@B@B@B@B@B@B@B .@X r5BMB: r ,, 7 B B@B @B@B@B@@ <br />
L@@B@B@B@ 8B@B@ BM:@B@B@B@B@B@@8X80Mu: FB@B@B@B@B@@@B@B@@@B@B q uO@GMFLv@B@B@B@B@ B@Bu <br />
@B@B@B@B k@ MYM@@@B@B@F ,. :5@B@B7 Y@B@@@@@B@@@B@@@@@B@@@@@B@ B : B@B@B@ @@B@BL <br />
B@@@@@@@ @@7 @EvB@BF B@B@B@@@@@B@BMB@B@B@B@@@B@B@B@ 7 . .@u, i@ B@B@77B@ <br />
B@B@B@@@O@ : 7., :@B@@@B@B@B@, .LB@@@B@B@B@B@B@B@ @ r@: @::M @@B@B@M@B@ <br />
:i @B@B@@@Bi5 :: v@B@@@B@B@B B@@@B@@@B@@@B@@ B@@@B@B@B@B@B@B@i<br />
: B@B@B@B@B@ @B@B@B@@@B LB@B@@@B@B@B@B@B@@5 @B@B@B@B@B@@@B@ <br />
.k@B@B@B@B@B@u. B@B@B@B@B2 @B@B@B@B@B@@@B@B@@@B@@@B@B@B@B@B@B@ <br />
:Lur:F@@@B@B@B@B@@@B B@B@B@B@B@ @@@B@B@B@B@B@@@B@B@B@B@B@B@B@B@B@J <br />
.vBMi :,,rB@B@B@B@BO @@@B@B@@@5 :i@@@B@B@B@@@B@B@B@B@@@B@@@B@B@B@@: <br />
1r @B@B@B@B@B@ LB@B@B@B@Bq N@Bi rB@B@B@B@B@B@B@@@B@B@B@B@B@B@@@B@ <br />
,L. @@B@B@B@G Li .@B@B@B@B@B@@@B@. B@B@viv@B@B@B@B@B@B@B@B@B@B@B@@@B@B@B@ <br />
r, @@@@@B@@@B@: : B@B@B@B@B@B@@@B@ :B@ @S@B@B@B@B@B@B@@@B@B@B@@@B@B@B@ <br />
.j iB@B@B@B@B@B@Bi:; G @@BrLk . i M@B@B@@@B@@@ GB@B@B@B@B@B@B@B@B@@@B@B@B@: <br />
,: : BUB@B@B@B@@@@@N0r@B@B B@B@ : :@B@B@B@@@B @B@B@B@B@B@B@B@B@B@B@B@. B <br />
@i ui M .. @B@: B.@@B@BB:O @. B @ i B@@@@@B@ @@@B@B@B@@@B @@B@B@B@@@B @ @ <br />
E@ @7 ; .U i N@B@ B .@ @ @B@B@B@B@ v .GB @B@B@B@B@@@M: @B@B@B@B@BZ @ Y <br />
Bu .@ M 7v7 @ :B@B@@@B@BU @B@B@B@B@ BB@B@B@B@B@Bi B@@@B@B@B@v <br />
5@ @7 L S .q .N@B@@@B@BBB@B@B@B@B@B@kqqSB@B@B@B@B@ @B@B@B@B@@r <br />
q : B Z .: 2@B@B@B@..L. . M@B@B@:@BiP @B B@@@B@B@B@ <br />
; B@@@B@B. @@@B@: 2@B@B@ i @B@@@B@B@B <br />
7@B@k@B@B@B@B@B@B@B@ B@B@@@@@Bi <br />
jB@B@B@@@B@@O @B@B@B@B@ <br />
B@B@B@B@k B@@@B@@@B <br />
rPS: @B@ @B@B@ <br />
. :: ,ui:,: vL:,:: B@B B@B@B <br />
.B@B@B@B@i @B@@@B@5 @B@B :@@@@@ OB@@@ @B@ @B@@@ <br />
@B@B@ FB@B@ 7@B@B@ .@@@B @B@B iMB@B@S .GB@B@.,B@@L vG0Sqv;:@ L@@ ..E@B <br />
B@@@B@@@B@B@B .@B@@ :B@B@ B@B@ @B@B@..B@B@ @B@@@2.B@B@ @B@BBM S@1 S@. <br />
@B@B@B. ,@B@B8 B@B@ .@B@@ @B@@ B@B@8:iii;Mv i@B@M .rr B@B@B@B k@r EJ <br />
S@B@B@B@ EB@B@B@B. B@B@B@, r@B@B@1 @B@B@B: YB@@@r. 7@B@B@2 @@@@@@MB@B@ ,Bi <br />
:r, .i ,: .i: :i ,:.i. i,:: :: :J@B@X7 i. i: r :,:. ,@ a <br />
.B n <br />
[ P R E S E N T S ] @ t <br />
@ i <br />
0 / <br />
B 4 <br />
@ 0 <br />
. 4 <br />
<br />
Good.Behavior.S01E03.PROPER.720p.HDTV.x264-KILLERS<br />
<br />
<br />
Day: 2016-11-29<br />
Resolution: 1280x720<br />
Size: 1.02 GiB<br />
FrameRate: 23.976<br />
Length: 00:49:02.144<br />
Bitrate: 2 535 Kbps<br />
Note: FLEET is missing the last seg<br />
<br />
<br />
n***** We all miss you. Come back soon.]]>
</description>
<pubDate>Tue, 29 Nov 2016 10:55:58 +0000</pubDate>
<link>https://alpharatio.cc/torrents.php?action=download&amp;authkey=private_auth_key&amp;torrent_pass=private_torrent_pass&amp;id=465960</link>
<guid>https://alpharatio.cc/torrents.php?action=download&amp;authkey=private_auth_key&amp;torrent_pass=private_torrent_pass&amp;id=465960</guid>
<comments>https://alpharatio.cc/torrents.php?id=465989</comments>
<dc:creator>Anonymous</dc:creator>
</item>
<item>
<title><![CDATA[TvHD 465860 465831 WWE.RAW.2016.11.28.720p.HDTV.x264-KYR]]></title>
<description>
<![CDATA[&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&deg;&deg; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&deg; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig;&deg;&deg;&Uuml;&deg;&Ucirc;&Ucirc;&sup2;&szlig;&Uuml;&Ucirc;&Ucirc;&Uuml;&Uuml;&sup2; &Uuml;&szlig;&sup2; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &Uuml;&szlig;&deg;&sup2;&deg;&sup2;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&plusmn;&sup2;&sup2; &Uuml;&Yacute; &THORN; &THORN;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&deg; &Ucirc;&Ucirc;&Yacute;&sup2;&THORN;&sup2;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&plusmn;&sup2;&Yacute;&Yacute;&THORN;&Ucirc; &szlig; &Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&sup2;&Ucirc;&Ucirc;&deg;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Yacute;&plusmn;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc;&THORN;&sup2;&THORN; &Yacute; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig; &szlig;&szlig;&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&deg;&Ucirc;&sup2;&Ucirc;&THORN;&sup2; &Yacute;&sup2; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&deg;&deg;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Yacute;&Ucirc;&Ucirc;&szlig;&Yacute;&sup2;&deg;&THORN;&THORN; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&deg;&Ucirc;&Yacute;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&THORN;&THORN;&THORN;&Uuml;&Ucirc;&Ucirc;&deg;&sup2;&Yacute;&THORN; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&sup2;&Yacute;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&deg;&Ucirc;&sup2;&THORN;&Ucirc;&Ucirc;&Ucirc; &THORN; &sup2; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &sup2;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Yacute;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Yacute;&Ucirc; &sup2; &Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&sup2;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Yacute;&Ucirc;&THORN;&Ucirc;&Ucirc;&THORN;&sup2;&THORN; &Yacute;&Yacute; &Uuml;&Uuml;&Uuml;&Uuml; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Uuml;&Uuml; &Uuml; &THORN;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&THORN;&Ucirc;&Ucirc;&sup2;&THORN;&deg;&THORN; &sup2;&Yacute; &szlig;&szlig;&szlig;&Ucirc;&Ucirc;&Ucirc;&sup2; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &Ucirc;&Ucirc;&sup2;&sup2;&Ucirc;&Ucirc;&sup2; &THORN;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&THORN;&Ucirc;&Yacute;&Ucirc;&Ucirc;&plusmn;&THORN; &sup2; &Yacute;&THORN; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&THORN; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&plusmn; &Uuml;&Uuml; &szlig;&sup2;&Ucirc;&Ucirc;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&THORN;&Yacute;&Ucirc;&Yacute;&Ucirc;&Ucirc;&deg;&Ucirc; &sup2; &THORN; &sup2; &Uuml;&szlig;&Ucirc;&Ucirc;&Ucirc;&szlig; &THORN;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Yacute; &Ucirc;&Ucirc;&szlig; &Uuml;&Uuml;&Uuml;&szlig;&sup2; &Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&THORN;&THORN;&Ucirc;&Uuml;&sup2; &THORN; &Yacute; &Yacute; &szlig;&szlig;&szlig; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&szlig; &sup2;&szlig; &sup2;&THORN;&Yacute; &THORN;&Ucirc;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Yacute;&Ucirc;&sup2;&THORN;&Ucirc;&Yacute;&Ucirc;&Yacute; &Yacute; &Yacute; &THORN; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &THORN; &THORN;&Yacute; &THORN;&Ucirc;<br />
&plusmn;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&THORN;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Yacute;&THORN;&Ucirc; &Yacute;&THORN; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Yacute; &sup2;&Ucirc;&Uuml; &Ucirc;&Ucirc;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&deg;&Ucirc; &szlig; &THORN; &Yacute; &Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Uuml;&Ucirc;&Ucirc;&Uuml; &Yacute; &Uuml;&szlig; &szlig;&Ucirc;&Ucirc;<br />
&Ucirc;&sup2;&Ucirc;&Ucirc;&Yacute;&Yacute;&Yacute;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&sup2;&THORN; &Yacute; &sup2;&Uuml;&sup2;&Ucirc;&Ucirc; &Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&Ucirc;&szlig;&szlig;&szlig; &Uuml;&Uuml;&Uuml;&sup2;&szlig; &Ucirc;&Ucirc;<br />
&Ucirc;&Yacute;&Ucirc;&Ucirc;&THORN;&Yacute;&deg;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Yacute;&Ucirc;&sup2;&Yacute; &Yacute; &szlig;&szlig;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &deg; &szlig;&sup2;&szlig; &sup2; &THORN;&Ucirc;<br />
&Ucirc;&Ucirc;&deg;&Ucirc;&THORN;&Ucirc;&THORN;&THORN;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc;&sup2;&THORN;&Ucirc; &Yacute; &Yacute; &Uuml;&Uuml; &THORN;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&Ucirc;&Uuml;&Uuml; &plusmn;&deg;&deg; &szlig; &Ucirc;<br />
&Ucirc;&Ucirc;&Ucirc;&THORN;&Yacute;&Ucirc;&THORN;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc; &sup2;&Yacute; &THORN; &THORN;&deg;&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &plusmn;&sup2;&plusmn;&plusmn; &THORN;<br />
&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Yacute;&Ucirc;&THORN;&Ucirc;&Ucirc;&Yacute;&sup2;&THORN;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Yacute;&THORN;&Yacute; &Yacute; &sup2;&szlig; &Uuml;&szlig;&Yacute;&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Uuml; &Uuml;&Uuml;&sup2;&Ucirc;&Ucirc;&Ucirc;&sup2;&sup2; &THORN;<br />
&Ucirc;&Ucirc;&Yacute;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&deg;&Ucirc;&sup2;&THORN;&Yacute;&Ucirc;&deg;&Ucirc;&THORN; &Yacute;&Yacute; &Uuml;&Uuml;&sup2;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&sup2;&Uuml; &Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&plusmn;<br />
&Ucirc;&szlig;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&THORN;&Ucirc;&sup2;&THORN;&Yacute;&Yacute;&Ucirc; &Yacute;&Yacute;&Yacute; &deg; &Yacute;&szlig;&Ucirc;&sup2;&Yacute;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&szlig;&szlig;&szlig; &szlig;&Uuml;&sup2;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&THORN;&Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc;&Ucirc; &sup2;&sup2;&plusmn;&plusmn;&THORN; &szlig;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Uuml;&szlig;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&sup2;&Yacute;&sup2;&Uuml; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&THORN;&Uuml; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute; &Uuml; &THORN;<br />
&szlig;&sup2;&Ucirc;&THORN;&sup2;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&THORN;&THORN;&Ucirc;&Ucirc;&sup2;&Ucirc;&sup2;&THORN;&sup2;&Yacute; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&THORN;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &THORN;&Ucirc;<br />
&Uuml;&sup2;&szlig;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&sup2;&Ucirc;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &Yacute;&Ucirc;<br />
&szlig; &Uuml;&Uuml;&szlig;&szlig;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&Ucirc;&szlig;&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &THORN; &Ucirc;<br />
&szlig; &szlig;&Ucirc;&Ucirc;&Uuml;&Uuml;&Yacute;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&Uuml;&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&Uuml;&Uuml;&szlig; &Yacute;&THORN;&sup2;<br />
&szlig;&Yacute;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&Uuml; &sup2; &Ucirc;&sup2;<br />
&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&THORN;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &sup2; &THORN;&sup2;&deg;<br />
&szlig; &sup2;&THORN;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&sup2; &sup2; &Uuml;&Ucirc;&sup2;<br />
&THORN;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&Ucirc; &sup2; &Uuml;&Ucirc;&sup2;&deg;<br />
&Uuml;&szlig; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&Yacute;&szlig; &Uuml;&szlig; &Uuml;&Ucirc;&sup2;&deg;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&Uuml;&sup2; &Uuml;&szlig; &Uuml;&Ucirc;&Ucirc;&sup2;&deg;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&sup2; &Uuml;&sup2;&szlig; &Uuml;&Ucirc;&Ucirc;&sup2;&plusmn;&deg;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&sup2; &Uuml;&Uuml;&szlig;&szlig; &Uuml;&Ucirc;&Ucirc;&sup2;&plusmn;&deg;<br />
&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&sup2; &Uuml;&Uuml;&szlig;&szlig; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&sup2;&plusmn;&deg;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&sup2; &Uuml;&Uuml;&szlig;&szlig; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&sup2;&plusmn;&deg;<br />
&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute;&Ucirc;&sup2;&Uuml;&Uuml;&szlig;&szlig; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&sup2;&sup2;&plusmn;&deg;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&szlig;&szlig;&szlig;&Uuml;&Uuml;&Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&sup2;&sup2;&plusmn;&plusmn;&deg;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&sup2;&sup2;&plusmn;&plusmn;&deg;<br />
&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &deg;&sup2;&szlig;&sup2;&sup2;&sup2;&sup2;&plusmn;&plusmn;&deg;<br />
&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &deg;&sup2;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute; &deg;&plusmn;&Yacute;<br />
&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&deg;&deg;&plusmn;&sup2;<br />
&sup2;&Ucirc;&Ucirc;&Ucirc;&sup2;&szlig;&sup2;&sup2;&szlig;<br />
&Ucirc;&sup2;&Ucirc;<br />
&THORN;&sup2;&Yacute;<br />
&plusmn;<br />
&deg;<br />
<br />
&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;<br />
&Uuml;&szlig;&szlig;&Ucirc;&Ucirc;&szlig; &szlig;&Ucirc;&sup2; &Uuml;&szlig;&szlig;&Ucirc;&Ucirc;&szlig; &szlig;&Ucirc;&sup2; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig; &szlig;&Ucirc;&sup2;<br />
&Ucirc;&Ucirc;&Ucirc;&deg;&plusmn;&Ucirc;&Yacute; &sup2;&Ucirc;&Uuml; &Ucirc;&Ucirc;&Ucirc;&deg;&plusmn;&Ucirc;&Yacute; &Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&deg;&plusmn;&Ucirc;&Yacute;<br />
&THORN;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc; &Ucirc;&Ucirc;&Yacute; &THORN;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Yacute;&Ucirc;&Ucirc;&Ucirc;&szlig; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&Ucirc;&Ucirc;<br />
&Uuml;&Uuml; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &THORN;&Ucirc;&Ucirc;&Yacute; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &sup2;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;<br />
&THORN;&Ucirc;&Ucirc; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&Ucirc;&Ucirc; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &THORN;&Ucirc;&Ucirc; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&Ucirc;&Ucirc;&Yacute; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &Ucirc;&Ucirc;&Ucirc; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Yacute; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;<br />
&THORN;&Ucirc;&sup2; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&Uuml;&Uuml; &THORN;&Ucirc;&Ucirc;&Yacute; &sup2;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &THORN;&Ucirc;&sup2; &Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Uuml;&Uuml;&Uuml; &szlig;<br />
&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig;&Ucirc;&Uuml; &sup2;&Ucirc;&Ucirc;&Uuml;&Uuml;&Uuml;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig;&Ucirc;&Uuml;<br />
&THORN;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig; &szlig;&Ucirc;&Ucirc;&Ucirc;&deg;&THORN;&Ucirc; &szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &THORN;&Ucirc;&Ucirc;&Ucirc;&szlig;&szlig; &szlig;&Ucirc;&Ucirc;&Ucirc;&deg;&THORN;&Ucirc;<br />
&sup2;&Ucirc;&sup2; &Ucirc;&Ucirc;&Ucirc;&Uuml;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Yacute; &sup2;&Ucirc;&Ucirc; &Ucirc;&Ucirc;&Ucirc;&Uuml;&Ucirc;&Yacute;<br />
&THORN;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2; &THORN;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &THORN;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;<br />
&Ucirc;&Ucirc;&Ucirc; &Ucirc;&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc; &Ucirc;&szlig;&Ucirc;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc;&Ucirc; &Ucirc;&szlig;&Ucirc;&Ucirc;&Ucirc;&Ucirc;<br />
&szlig; &Ucirc;&deg;&THORN;&Ucirc;&Ucirc;&Ucirc;&Yacute; &Ucirc;&deg;&THORN;&Ucirc;&Ucirc;&Ucirc; &szlig; &Ucirc;&deg;&THORN;&Ucirc;&Ucirc;&Ucirc;&Yacute;<br />
&Ucirc;&plusmn;&deg;&Ucirc;&Ucirc;&Ucirc;&sup2; &Ucirc;&plusmn;&deg;&Ucirc;&Ucirc;&Ucirc;&sup2; &Ucirc;&plusmn;&deg;&Ucirc;&Ucirc;&Ucirc;&sup2;<br />
&THORN;&plusmn;&plusmn;&plusmn;&deg;&Ucirc;&Ucirc; &THORN;&plusmn;&plusmn;&plusmn;&deg;&Ucirc;&Ucirc; &THORN;&plusmn;&plusmn;&plusmn;&deg;&Ucirc;&Ucirc; presents..<br />
&THORN;&sup2;&plusmn;&plusmn;&plusmn;&plusmn;&Yacute; &THORN;&sup2;&plusmn;&plusmn;&plusmn;&plusmn;&Yacute; &THORN;&sup2;&plusmn;&plusmn;&plusmn;&plusmn;&Yacute;<br />
&Ucirc;&sup2;&sup2;&sup2;&Ucirc;&Uuml; &Uuml;&sup2; &Ucirc;&sup2;&sup2;&sup2;&Ucirc;&Uuml; &Uuml;&sup2; &Ucirc;&sup2;&sup2;&sup2;&Ucirc;&Uuml; &Uuml;&sup2;<br />
&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;<br />
k n o w y o u r r o l e<br />
<br />
&uacute; &uacute;&uacute;--&Auml;-&Auml;-&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;-&Auml;-&Auml;--&uacute;&uacute; &uacute;<br />
WWE.RAW.2016.11.28.720p.HDTV.h264-KYR<br />
&uacute; &uacute;&uacute;--&Auml;-&Auml;-&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;-&Auml;-&Auml;--&uacute;&uacute; &uacute;<br />
&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;<br />
&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Ucirc;&sup2;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Uuml;&szlig;&Ucirc; &Uuml;&Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Ucirc;&Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&Uuml;&Ucirc;&deg;&Uuml;&szlig;&Ucirc;<br />
&Uacute;&Auml;&Auml;&Ucirc; &szlig;&Uuml;&Ucirc; &Uuml;&Ucirc;&Ucirc; &Ucirc;&sup2;&Ucirc; &Uuml;&Ucirc;&Ucirc; &Uuml; &Ucirc;&Uuml;&Uuml;&deg;&Ucirc; &Uuml;&Ucirc;&szlig;&Auml;&Auml;&Ucirc; &Ucirc; &Ucirc; &Ucirc; &Uuml;&Ucirc;&Ucirc; &Ucirc; &Ucirc;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&uacute;&uacute; &uacute;<br />
&sup3; &Ucirc; &Ucirc; &Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&Ucirc; &Ucirc;&Uuml;&szlig; &Ucirc;&Uuml;&szlig;&szlig;&Ucirc; &Ucirc; &Ucirc;&Uuml;&Ucirc; &Ucirc;&deg;&Ucirc;&sup2;&Ucirc; &szlig; &Ucirc;<br />
&sup3; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;<br />
&sup3;<br />
&sup3; title&uacute;[ WWE RAW ]&uacute;<br />
&sup3; genre&uacute;[ Wrestling ]&uacute; crf&uacute;[ 23 ]&uacute;<br />
&sup3; rel. date&uacute;[ 11.28.16 ]&uacute; format&uacute;[ x264 ]&uacute;<br />
&sup3; air date&uacute;[ 11.28.16 ]&uacute; source&uacute;[ HDTV ]&uacute;<br />
&sup3; runtime&uacute;[ 2h 13m 48s ]&uacute; bitrate&uacute;[ 4111kbps ]&uacute;<br />
&sup3; filesize&uacute;[ 4.28 GB ]&uacute; resolu.&uacute;[ 1280x720 ]&uacute;<br />
&sup3; rar count&uacute;[ 93x50mb ]&uacute; frames&uacute;[ 59.940 ]&uacute;<br />
&sup3; &uacute;[ audio&uacute;[ 384 kbps AC3 5.1 ]&uacute;<br />
&sup3; &uacute;[ location&uacute;[ USA ]&uacute;<br />
&sup3; &uacute;[ ]&uacute;<br />
&sup3; url &uacute;[ http://www.wwe.com ]&uacute; <br />
&sup3;<br />
&sup3;<br />
&sup3; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;<br />
&sup3; &Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Ucirc;&sup2;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Uuml;&szlig;&Ucirc; &Uuml;&Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Uuml;&szlig;&Ucirc;&Uuml; &Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Uuml;&Uuml;&Ucirc;<br />
&sup3; &uacute; &uacute;&uacute;&Auml;&Auml;&Auml;&Auml;&Auml;-&Ucirc; &szlig;&Uuml;&Ucirc; &Uuml;&Ucirc;&Ucirc; &Ucirc;&sup2;&Ucirc; &Uuml;&Ucirc;&Ucirc; &Uuml; &Ucirc;&Uuml;&Uuml;&deg;&Ucirc; &Uuml;&Ucirc;&szlig;&Auml;&Auml;&Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc;&Ucirc; &Ucirc;&Ucirc; &Uuml;&Ucirc;&Ucirc;&Uuml;&Uuml;&deg;&Ucirc;&Auml;&Auml;&acute;<br />
&sup3; &Ucirc; &Ucirc; &Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&Ucirc; &Ucirc;&Uuml;&szlig; &Ucirc;&Uuml;&szlig;&szlig;&Ucirc; &Ucirc; &Ucirc; &Ucirc; &szlig; &Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig; &Ucirc; &sup3;<br />
&sup3; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &sup3;<br />
&sup3; &sup3;<br />
&sup3; &sup3;<br />
&sup3; Enjoy! &sup3;<br />
&sup3; &sup3;<br />
&sup3; &sup3;<br />
&sup3; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &sup3;<br />
&sup3; &Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Uuml;&szlig;&Ucirc;&szlig;&Ucirc;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Ucirc;&Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&Uuml;&Ucirc;&deg;&Uuml;&szlig;&Ucirc; &sup3;<br />
&Atilde;&Auml;&Auml;&Ucirc; &Yacute;&szlig;&Ucirc; &szlig;&Uuml;&Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &szlig; &Ucirc;&Auml;&Auml;&Ucirc;&deg;&Ucirc; &Ucirc; &Ucirc; &Uuml;&Ucirc;&Ucirc; &Ucirc; &Ucirc;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;-&Auml;&Auml;&Auml;&Auml;&Auml;&uacute;&uacute; &uacute; &sup3;<br />
&Ucirc; &szlig; &Ucirc; &Ucirc; &Ucirc; &szlig; &Ucirc; &szlig; &Ucirc; &Ucirc;&szlig;&szlig; &Ucirc; &Ucirc; &Ucirc; &Ucirc;&deg;&Ucirc;&sup2;&Ucirc; &szlig; &Ucirc; &sup3;<br />
&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig; &sup3;<br />
&sup3;<br />
 group info &sup3;<br />
&sup3;<br />
Know Your Role and Shut Your Mouth! &sup3;<br />
&sup3;<br />
 we are now looking for... &sup3;<br />
&sup3;<br />
(a) capper(s) of cable, PPV, good upspeed advantageous &sup3;<br />
.. contact in the usual way. &sup3;<br />
&sup3;<br />
 KYR respects... &sup3;<br />
&sup3;<br />
everyone keeping it real and oldschool. we love ya! &sup3;<br />
&sup3;<br />
&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &sup3;<br />
&Uuml;&Uuml;&Uuml;&Uuml;&sup2; &Uuml;&Uuml;&Uuml; &Ucirc;&Uuml;&sup2; &Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &sup2;&Yacute; &sup3;<br />
&uacute; &uacute;&uacute;&Auml;&Auml;&Auml;&Auml;&Auml;--&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Ucirc; &Uuml;&Uuml; &Yacute;&THORN;&Ucirc;&Ucirc;&Yacute;&Uuml;&Uuml; &Yacute;&THORN;&Ucirc;&Ucirc;&Yacute;&szlig;&szlig; &THORN;&Ucirc;&Ucirc;&Yacute;&THORN;&Ucirc; &Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&acute;<br />
&Ucirc; &Ucirc;&Ucirc; &Uuml;&Ucirc;&Ucirc;&szlig; &Ucirc;&Ucirc; &Uuml;&Ucirc;&Ucirc;&sup2; &Ucirc;&Ucirc; &Uuml;&Ucirc;&Ucirc;&szlig; &Ucirc;&Yacute; K N O W &sup3;<br />
ascii crafted by &Ucirc; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&Uuml; &THORN;&Ucirc;&Ucirc;&sup2;&szlig; &Uuml; &Ucirc;&Ucirc;&Ucirc;&Ucirc;&sup2;&Uuml; &szlig;&Ucirc; &sup3;<br />
&Ucirc; &Ucirc;&Ucirc; &szlig;&Ucirc;&Ucirc;&sup2; &Ucirc;&Ucirc; &Uuml;&sup2;&Ucirc; &Ucirc;&Ucirc; &szlig;&Ucirc;&Ucirc;&sup2; &sup2;&Yacute; Y O U R &sup3;<br />
h8`!HiGHONASCii &Ucirc; &Ucirc;&Ucirc; &Yacute;&THORN;&Ucirc;&Ucirc;&Yacute; &Ucirc;&Ucirc; &Ucirc; &Ucirc; &Ucirc;&Ucirc; &Yacute;&THORN;&Ucirc;&Ucirc;&Yacute;&THORN;&Ucirc; &sup3;<br />
&Ucirc; &Ucirc;&sup2; &Ucirc; &Ucirc;&Ucirc;&sup2; &Ucirc;&sup2; &Ucirc; &Ucirc; &Ucirc;&sup2; &Ucirc; &Ucirc;&Ucirc;&sup2; &Ucirc; R O L E &sup3;<br />
&uacute; &uacute;&uacute;&Auml;-&Auml;----&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Ucirc;&Uuml;&Uuml;&Uuml;&Uuml;&sup2;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&sup2; &Ucirc;&Uuml;&Uuml;&Uuml;&Uuml;&sup2;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&sup2; &Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Auml;&Ugrave;<br />
&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;<br />
&deg;&plusmn;&sup2;&Ucirc; &Uuml;&szlig;&Ucirc; &Uuml;&szlig;&Ucirc; &Uuml;&szlig;&Ucirc; &Uuml;&szlig;&Ucirc;&sup2;&sup2;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Ucirc;&sup2;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Uuml;&szlig;&Ucirc; &Uuml;&Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc; &Uuml;&Uuml;&Ucirc;&sup2;&sup2;&Ucirc;&deg;&Uuml;&szlig;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Uuml;&szlig;&Ucirc;&sup2;&plusmn;&deg;<br />
&deg; &deg;&plusmn;&Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc;+&plusmn;&Ucirc; &szlig;&Uuml;&Ucirc; &Uuml;&Ucirc;&Ucirc; &Ucirc;&plusmn;&Ucirc; &Uuml;&Ucirc;&Ucirc; &Uuml; &Ucirc;&Uuml;&Uuml;&deg;&Ucirc; &Uuml;&Ucirc;&Ucirc;&Uuml;&Uuml;&deg;&Ucirc;&plusmn;&plusmn;&Ucirc; &Uuml; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc;&plusmn;&deg; &deg;<br />
&deg;&plusmn;&sup2;&Ucirc;&Uuml;&szlig;&deg;&Ucirc;&Uuml;&szlig;&deg;&Ucirc;&Uuml;&szlig;&deg;&Ucirc;&Uuml;&szlig;&deg;&Ucirc;&sup2;&sup2;&Ucirc; &Ucirc; &Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&Ucirc; &Ucirc;&Uuml;&szlig; &Ucirc;&Uuml;&szlig;&szlig;&Ucirc;&Uuml;&szlig; &Ucirc;&sup2;&sup2;&Ucirc;&Uuml;&Ucirc; &Ucirc;&Uuml;&Ucirc; &Ucirc; &szlig;&Uuml;&Ucirc;&sup2;&plusmn;&deg;<br />
&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;<br />
&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml; &Uuml;&Uuml; &Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;&Uuml;<br />
&deg;&plusmn;&sup2;&sup2;&Ucirc;&szlig;&Uuml; &Ucirc;&deg;&Uuml;&szlig;&Ucirc;&szlig;&Ucirc;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&Uuml; &Uuml;&Ucirc;&Uuml;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&szlig;&Uuml;&deg;&Ucirc;&deg;&Ucirc;&deg;&Ucirc;&deg;&Ucirc;&sup2;&sup2;&plusmn;&deg;<br />
&deg; &deg;&plusmn;&plusmn;&Ucirc; &Ucirc;&Ucirc;&Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc; &Ucirc;&Ucirc; &Ucirc;&Ucirc;&deg;&Ucirc; &Ucirc; &Ucirc; &Yacute;&szlig;&Ucirc; &Ucirc; &Ucirc; &Ucirc;&plusmn;&plusmn;&deg; &deg;<br />
&deg;&plusmn;&sup2;&sup2;&Ucirc;&Uuml;&szlig;&deg;&Ucirc; &szlig; &Ucirc; &szlig; &Ucirc;&Uuml;&Ucirc; &Ucirc;&Ucirc;&deg;&Ucirc;&Ucirc; &Ucirc; &Ucirc; &Ucirc;&deg;&szlig; &Ucirc;&szlig;&Ucirc;&szlig;&Ucirc;&szlig;&Ucirc;&sup2;&sup2;&plusmn;&deg;<br />
&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig; &szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;&szlig;]]>
</description>
<pubDate>Tue, 29 Nov 2016 05:08:18 +0000</pubDate>
<link>https://alpharatio.cc/torrents.php?action=download&amp;authkey=private_auth_key&amp;torrent_pass=private_torrent_pass&amp;id=465831</link>
<guid>https://alpharatio.cc/torrents.php?action=download&amp;authkey=private_auth_key&amp;torrent_pass=private_torrent_pass&amp;id=465831</guid>
<comments>https://alpharatio.cc/torrents.php?id=465860</comments>
<dc:creator>Anonymous</dc:creator>
</item>
</channel>
</rss>

View File

@@ -0,0 +1,98 @@
<?xml version='1.0' encoding='UTF-8' ?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title>limetorrents.cc - RSS Feed</title>
<link>http://www.limetorrents.cc/</link>
<description>Latest Torrents RSS.</description>
<language>en-us</language>
<pubDate>Thu, 16 Feb 2017 05:48:36 +0200</pubDate>
<lastBuildDate>Thu, 16 Feb 2017 05:48:36 +0200</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>limetorrents.cc RSS Generator 1.1</generator>
<item>
<title>The Expanse 2x04 (720p-HDTV-x264-SVA)[VTV]</title>
<guid isPermaLink='true'>http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html</guid>
<pubDate>16 Feb 2017 05:24:26 +0300</pubDate>
<category>TV shows</category>
<link>http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html</link>
<size>880496711</size>
<description>
<![CDATA[
Category: <a href="http://www.limetorrents.cc/browse-torrents/TV-shows/">TV shows</a><br />
Seeds: 0<br />Leechers: 0<br />Size: 839.71 MB<br /><br /><a href="http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html">More @ limetorrents.cc</a><br /> ]]>
</description>
<comments>http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html</comments>
<category domain="http://www.limetorrents.cc/browse-torrents/TV shows">TV shows</category>
<enclosure url="http://itorrents.org/torrent/51C578C9823DD58F6EEA287C368ED935843D63AB.torrent?title=The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]" length="880496711" type="application/x-bittorrent" />
</item>
<item>
<title>Criminal Minds S12E13 720p HDTV x264-FLEET[PRiME]</title>
<guid isPermaLink='true'>http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html</guid>
<pubDate>16 Feb 2017 05:20:49 +0300</pubDate>
<category>TV shows</category>
<link>http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html</link>
<size>940818158</size>
<description>
<![CDATA[
Category: <a href="http://www.limetorrents.cc/browse-torrents/TV-shows/">TV shows</a><br />
Seeds: 0<br />Leechers: 0<br />Size: 897.23 MB<br /><br /><a href="http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html">More @ limetorrents.cc</a><br /> ]]>
</description>
<comments>http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html</comments>
<category domain="http://www.limetorrents.cc/browse-torrents/TV shows">TV shows</category>
<enclosure url="http://itorrents.org/torrent/C7EBCBE53A82E7C8F0826417F5174C8709DB9DC0.torrent?title=Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]" length="940818158" type="application/x-bittorrent" />
</item>
<item>
<title>Legion S01E02 720p HDTV x264-AVS[PRiME]</title>
<guid isPermaLink='true'>http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html</guid>
<pubDate>16 Feb 2017 05:20:48 +0300</pubDate>
<category>TV shows</category>
<link>http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html</link>
<size>1320654292</size>
<description>
<![CDATA[
Category: <a href="http://www.limetorrents.cc/browse-torrents/TV-shows/">TV shows</a><br />
Seeds: 0<br />Leechers: 0<br />Size: 1.23 GB<br /><br /><a href="http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html">More @ limetorrents.cc</a><br /> ]]>
</description>
<comments>http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html</comments>
<category domain="http://www.limetorrents.cc/browse-torrents/TV shows">TV shows</category>
<enclosure url="http://itorrents.org/torrent/ED2903DB3F4B3D728D2E7091C33B6F502A0FB5D4.torrent?title=Legion-S01E02-720p-HDTV-x264-AVS[PRiME]" length="1320654292" type="application/x-bittorrent" />
</item>
<item>
<title>Suits S06E14 HDTV x264-SVA[PRiME]</title>
<guid isPermaLink='true'>http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html</guid>
<pubDate>16 Feb 2017 05:11:58 +0300</pubDate>
<category>TV shows</category>
<link>http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html</link>
<size>212274667</size>
<description>
<![CDATA[
Category: <a href="http://www.limetorrents.cc/browse-torrents/TV-shows/">TV shows</a><br />
Seeds: 0<br />Leechers: 0<br />Size: 202.44 MB<br /><br /><a href="http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html">More @ limetorrents.cc</a><br /> ]]>
</description>
<comments>http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html</comments>
<category domain="http://www.limetorrents.cc/browse-torrents/TV shows">TV shows</category>
<enclosure url="http://itorrents.org/torrent/5E412B3200773684AEDBEBF9B053ED58180279DD.torrent?title=Suits-S06E14-HDTV-x264-SVA[PRiME]" length="212274667" type="application/x-bittorrent" />
</item>
<item>
<title>The Expanse S02E04 HDTV x264-SVA[PRiME]</title>
<guid isPermaLink='true'>http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html</guid>
<pubDate>16 Feb 2017 05:11:57 +0300</pubDate>
<category>TV shows</category>
<link>http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html</link>
<size>269445781</size>
<description>
<![CDATA[
Category: <a href="http://www.limetorrents.cc/browse-torrents/TV-shows/">TV shows</a><br />
Seeds: 0<br />Leechers: 0<br />Size: 256.96 MB<br /><br /><a href="http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html">More @ limetorrents.cc</a><br /> ]]>
</description>
<comments>http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html</comments>
<category domain="http://www.limetorrents.cc/browse-torrents/TV shows">TV shows</category>
<enclosure url="http://itorrents.org/torrent/7E552CD2D99E43C34FBB233E3BAF0C1ECD416C76.torrent?title=The-Expanse-S02E04-HDTV-x264-SVA[PRiME]" length="269445781" type="application/x-bittorrent" />
</item>
</channel>
</rss>

View File

@@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Womble's NZB Index</title>
<link>http://indexer.local/</link>
<description>NZB Index</description>
<webMaster>my.email@internet.me</webMaster>
<ttl>15</ttl>
<item>
<title>One.Child.S01E01.720p.HDTV.x264-TLA</title>
<link>http://indexer.local/nzb/bb4/One.Child.S01E01.720p.HDTV.x264-TLA.nzb</link>
<description>
One.Child.S01E01.720p.HDTV.x264-TLA
(Size:956 Mb)
</description>
<category>tv-hd</category>
<pubDate>2/17/2016 11:03:52 PM</pubDate>
<guid isPermaLink="true">http://indexer.local/nzb/bb4/One.Child.S01E01.720p.HDTV.x264-TLA.nzb</guid>
<enclosure url="http://indexer.local/nzb/bb4/One.Child.S01E01.720p.HDTV.x264-TLA.nzb" length="2048" type="text/xml" />
</item>
<item>
<title>Midsomer.Murders.S18E06.Harvest.Of.Souls.HDTV.x264-ORGANiC</title>
<link>http://indexer.local/nzb/17c/Midsomer.Murders.S18E06.Harvest.Of.Souls.HDTV.x264-ORGANiC.nzb</link>
<description>
Midsomer.Murders.S18E06.Harvest.Of.Souls.HDTV.x264-ORGANiC
(Size:730 Mb)
</description>
<category>tv-sd</category>
<pubDate>2/17/2016 10:55:33 PM</pubDate>
<guid isPermaLink="true">http://indexer.local/nzb/17c/Midsomer.Murders.S18E06.Harvest.Of.Souls.HDTV.x264-ORGANiC.nzb</guid>
<enclosure url="http://indexer.local/nzb/17c/Midsomer.Murders.S18E06.Harvest.Of.Souls.HDTV.x264-ORGANiC.nzb" length="2048" type="text/xml" />
</item>
<item>
<title>Forget.and.Forgive.2014.HDTV.x264-SQUEAK</title>
<link>http://indexer.local/nzb/f3f/Forget.and.Forgive.2014.HDTV.x264-SQUEAK.nzb</link>
<description>
Forget.and.Forgive.2014.HDTV.x264-SQUEAK
(Size:719 Mb)
</description>
<category>tv-sd</category>
<pubDate>2/17/2016 10:25:28 PM</pubDate>
<guid isPermaLink="true">http://indexer.local/nzb/f3f/Forget.and.Forgive.2014.HDTV.x264-SQUEAK.nzb</guid>
<enclosure url="http://indexer.local/nzb/f3f/Forget.and.Forgive.2014.HDTV.x264-SQUEAK.nzb" length="2048" type="text/xml" />
</item>
<item>
<title>National.Geographic.The.Lakeshore.Killers.HDTV.x264-SQUEAK</title>
<link>http://indexer.local/nzb/828/National.Geographic.The.Lakeshore.Killers.HDTV.x264-SQUEAK.nzb</link>
<description>
National.Geographic.The.Lakeshore.Killers.HDTV.x264-SQUEAK
(Size:436 Mb)
</description>
<category>tv-sd</category>
<pubDate>2/17/2016 10:20:36 PM</pubDate>
<guid isPermaLink="true">http://indexer.local/nzb/828/National.Geographic.The.Lakeshore.Killers.HDTV.x264-SQUEAK.nzb</guid>
<enclosure url="http://indexer.local/nzb/828/National.Geographic.The.Lakeshore.Killers.HDTV.x264-SQUEAK.nzb" length="2048" type="text/xml" />
</item>
<item>
<title>Desert.Lands.of.The.Middle.East.E01.Turkeys.Harsh.Paradise.HDTV.x264-SQUEAK</title>
<link>http://indexer.local/nzb/210/Desert.Lands.of.The.Middle.East.E01.Turkeys.Harsh.Paradise.HDTV.x264-SQUEAK.nzb</link>
<description>
Desert.Lands.of.The.Middle.East.E01.Turkeys.Harsh.Paradise.HDTV.x264-SQUEAK
(Size:460 Mb)
</description>
<category>tv-sd</category>
<pubDate>2/17/2016 10:18:29 PM</pubDate>
<guid isPermaLink="true">http://indexer.local/nzb/210/Desert.Lands.of.The.Middle.East.E01.Turkeys.Harsh.Paradise.HDTV.x264-SQUEAK.nzb</guid>
<enclosure url="http://indexer.local/nzb/210/Desert.Lands.of.The.Middle.East.E01.Turkeys.Harsh.Paradise.HDTV.x264-SQUEAK.nzb" length="2048" type="text/xml" />
</item>
</channel>
</rss>

View File

@@ -99,7 +99,6 @@ namespace NzbDrone.Core.Test.Framework
{
WithTempAsAppPath();
Mocker.SetConstant<IAnnouncer>(Mocker.Resolve<MigrationLogger>());
Mocker.SetConstant<IConnectionStringFactory>(Mocker.Resolve<ConnectionStringFactory>());
Mocker.SetConstant<IMigrationController>(Mocker.Resolve<MigrationController>());

View File

@@ -12,6 +12,7 @@ namespace NzbDrone.Core.Test.Framework
{
List<Dictionary<string, object>> Query(string sql);
List<T> Query<T>(string sql) where T : new();
T QueryScalar<T>(string sql);
}
public class DirectDataMapper : IDirectDataMapper
@@ -25,7 +26,7 @@ namespace NzbDrone.Core.Test.Framework
_providerFactory = dataMapper.ProviderFactory;
_connectionString = dataMapper.ConnectionString;
}
private DbConnection OpenConnection()
{
var connection = _providerFactory.CreateConnection();
@@ -62,6 +63,13 @@ namespace NzbDrone.Core.Test.Framework
return dataTable.Rows.Cast<DataRow>().Select(MapToObject<T>).ToList();
}
public T QueryScalar<T>(string sql)
{
var dataTable = GetDataTable(sql);
return dataTable.Rows.Cast<DataRow>().Select(d => MapValue(d, 0, typeof(T))).Cast<T>().FirstOrDefault();
}
protected Dictionary<string, object> MapToDictionary(DataRow dataRow)
{
var item = new Dictionary<string, object>();
@@ -107,24 +115,29 @@ namespace NzbDrone.Core.Test.Framework
propertyType = propertyType.GetGenericArguments()[0];
}
object value;
if (dataRow.ItemArray[i] == DBNull.Value)
{
value = null;
}
else if (dataRow.Table.Columns[i].DataType == typeof(string) && propertyType != typeof(string))
{
value = Json.Deserialize((string)dataRow.ItemArray[i], propertyType);
}
else
{
value = Convert.ChangeType(dataRow.ItemArray[i], propertyType);
}
object value = MapValue(dataRow, i, propertyType);
propertyInfo.SetValue(item, value, null);
}
return item;
}
private object MapValue(DataRow dataRow, int i, Type targetType)
{
if (dataRow.ItemArray[i] == DBNull.Value)
{
return null;
}
else if (dataRow.Table.Columns[i].DataType == typeof(string) && targetType != typeof(string))
{
return Json.Deserialize((string)dataRow.ItemArray[i], targetType);
}
else
{
return Convert.ChangeType(dataRow.ItemArray[i], targetType);
}
}
}
}

View File

@@ -1,8 +1,8 @@
using System;
using FluentMigrator;
using FluentMigrator.Runner;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration.Framework;
using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.Framework
{
@@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.Framework
BeforeMigration = m =>
{
var migration = m as TMigration;
if (beforeMigration != null && migration is TMigration)
if (beforeMigration != null && migration != null)
{
beforeMigration(migration);
}
@@ -39,10 +39,8 @@ namespace NzbDrone.Core.Test.Framework
[SetUp]
public override void SetupDb()
{
Mocker.SetConstant<IAnnouncer>(Mocker.Resolve<MigrationLogger>());
SetupContainer();
}
[Obsolete("Don't use Mocker/Repositories in MigrationTests, query the DB.", true)]
public new AutoMoqer Mocker => base.Mocker;
}
}

View File

@@ -1,4 +1,5 @@
using FluentAssertions;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.HealthCheck;
namespace NzbDrone.Core.Test.HealthCheck.Checks
@@ -10,14 +11,24 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
result.Type.Should().Be(HealthCheckResult.Ok);
}
public static void ShouldBeWarning(this Core.HealthCheck.HealthCheck result)
public static void ShouldBeWarning(this Core.HealthCheck.HealthCheck result, string message = null)
{
result.Type.Should().Be(HealthCheckResult.Warning);
if (message.IsNotNullOrWhiteSpace())
{
result.Message.Should().Contain(message);
}
}
public static void ShouldBeError(this Core.HealthCheck.HealthCheck result)
public static void ShouldBeError(this Core.HealthCheck.HealthCheck result, string message = null)
{
result.Type.Should().Be(HealthCheckResult.Error);
if (message.IsNotNullOrWhiteSpace())
{
result.Message.Should().Contain(message);
}
}
}
}

View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class IndexerRssCheckFixture : CoreTest<IndexerRssCheck>
{
private Mock<IIndexer> _indexerMock;
[SetUp]
public void SetUp()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.GetAvailableProviders())
.Returns(new List<IIndexer>());
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.RssEnabled(It.IsAny<bool>()))
.Returns(new List<IIndexer>());
}
private void GivenIndexer(bool supportsRss, bool supportsSearch)
{
_indexerMock = Mocker.GetMock<IIndexer>();
_indexerMock.SetupGet(s => s.SupportsRss).Returns(supportsRss);
_indexerMock.SetupGet(s => s.SupportsSearch).Returns(supportsSearch);
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.GetAvailableProviders())
.Returns(new List<IIndexer> { _indexerMock.Object });
}
private void GivenRssEnabled()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.RssEnabled(It.IsAny<bool>()))
.Returns(new List<IIndexer> { _indexerMock.Object });
}
private void GivenRssFiltered()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.RssEnabled(false))
.Returns(new List<IIndexer> { _indexerMock.Object });
}
[Test]
public void should_return_error_when_no_indexer_present()
{
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_error_when_no_rss_supported_indexer_present()
{
GivenIndexer(false, true);
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_ok_when_rss_is_enabled()
{
GivenIndexer(true, false);
GivenRssEnabled();
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_error_if_rss_is_supported_but_disabled()
{
GivenIndexer(true, false);
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_filter_warning_if_rss_is_enabled_but_filtered()
{
GivenIndexer(true, false);
GivenRssFiltered();
Subject.Check().ShouldBeWarning("recent indexer errors");
}
}
}

View File

@@ -8,10 +8,22 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class IndexerCheckFixture : CoreTest<IndexerCheck>
public class IndexerSearchCheckFixture : CoreTest<IndexerSearchCheck>
{
private Mock<IIndexer> _indexerMock;
[SetUp]
public void SetUp()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.GetAvailableProviders())
.Returns(new List<IIndexer>());
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.SearchEnabled(It.IsAny<bool>()))
.Returns(new List<IIndexer>());
}
private void GivenIndexer(bool supportsRss, bool supportsSearch)
{
_indexerMock = Mocker.GetMock<IIndexer>();
@@ -21,42 +33,30 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.GetAvailableProviders())
.Returns(new List<IIndexer> { _indexerMock.Object });
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.RssEnabled())
.Returns(new List<IIndexer>());
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.SearchEnabled())
.Returns(new List<IIndexer>());
}
private void GivenRssEnabled()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.RssEnabled())
.Returns(new List<IIndexer> { _indexerMock.Object });
}
private void GivenSearchEnabled()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.SearchEnabled())
.Setup(s => s.SearchEnabled(It.IsAny<bool>()))
.Returns(new List<IIndexer> { _indexerMock.Object });
}
private void GivenSearchFiltered()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.SearchEnabled(false))
.Returns(new List<IIndexer> { _indexerMock.Object });
}
[Test]
public void should_return_error_when_not_indexers_are_enabled()
public void should_return_warning_when_no_indexer_present()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.GetAvailableProviders())
.Returns(new List<IIndexer>());
Subject.Check().ShouldBeError();
Subject.Check().ShouldBeWarning();
}
[Test]
public void should_return_warning_when_only_enabled_indexer_doesnt_support_search()
public void should_return_warning_when_no_search_supported_indexer_present()
{
GivenIndexer(true, false);
@@ -64,7 +64,16 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
}
[Test]
public void should_return_warning_when_only_enabled_indexer_doesnt_support_rss()
public void should_return_ok_when_search_is_enabled()
{
GivenIndexer(false, true);
GivenSearchEnabled();
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_warning_if_search_is_supported_but_disabled()
{
GivenIndexer(false, true);
@@ -72,52 +81,12 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
}
[Test]
public void should_return_ok_when_multiple_indexers_are_enabled()
public void should_return_filter_warning_if_search_is_enabled_but_filtered()
{
GivenRssEnabled();
GivenSearchEnabled();
GivenIndexer(false, true);
GivenSearchFiltered();
var indexer1 = Mocker.GetMock<IIndexer>();
indexer1.SetupGet(s => s.SupportsRss).Returns(true);
indexer1.SetupGet(s => s.SupportsSearch).Returns(true);
var indexer2 = new Moq.Mock<IIndexer>();
indexer2.SetupGet(s => s.SupportsRss).Returns(true);
indexer2.SetupGet(s => s.SupportsSearch).Returns(false);
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.GetAvailableProviders())
.Returns(new List<IIndexer> { indexer1.Object, indexer2.Object });
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_ok_when_indexer_supports_rss_and_search()
{
GivenIndexer(true, true);
GivenRssEnabled();
GivenSearchEnabled();
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_warning_if_rss_is_supported_but_disabled()
{
GivenIndexer(true, true);
GivenSearchEnabled();
Subject.Check().ShouldBeWarning();
}
[Test]
public void should_return_warning_if_search_is_supported_but_disabled()
{
GivenIndexer(true, true);
GivenRssEnabled();
Subject.Check().ShouldBeWarning();
Subject.Check().ShouldBeWarning("recent indexer errors");
}
}
}

View File

@@ -81,10 +81,10 @@ namespace NzbDrone.Core.Test.HistoryTests
Path = @"C:\Test\Unsorted\Series.s01e01.mkv"
};
Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, true, "sab", "abcd", true));
Subject.Handle(new EpisodeImportedEvent(localEpisode, episodeFile, true, "sab", "abcd"));
Mocker.GetMock<IHistoryRepository>()
.Verify(v => v.Insert(It.Is<History.History>(h => h.SourceTitle == Path.GetFileNameWithoutExtension(localEpisode.Path))));
}
}
}
}

View File

@@ -28,7 +28,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
_mockIndexer.SetupGet(s => s.SupportsSearch).Returns(true);
Mocker.GetMock<IIndexerFactory>()
.Setup(s => s.SearchEnabled())
.Setup(s => s.SearchEnabled(true))
.Returns(new List<IIndexer> { _mockIndexer.Object });
Mocker.GetMock<IMakeDownloadDecision>()

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests
Subject.Definition = new IndexerDefinition()
{
Name = "BroadcastheNet",
Settings = new BroadcastheNetSettings() { ApiKey = "abc", BaseUrl = "https://api.btnapps.net/" }
Settings = new BroadcastheNetSettings() { ApiKey = "abc", BaseUrl = "https://api.broadcasthe.net/" }
};
}
@@ -139,7 +139,7 @@ namespace NzbDrone.Core.Test.IndexerTests.BroadcastheNetTests
{
var recentFeed = ReadAllText(@"Files/Indexers/BroadcastheNet/RecentFeed.json");
(Subject.Definition.Settings as BroadcastheNetSettings).BaseUrl = "http://api.btnapps.net/";
(Subject.Definition.Settings as BroadcastheNetSettings).BaseUrl = "http://api.broadcasthe.net/";
recentFeed = recentFeed.Replace("http:", "https:");

View File

@@ -5,7 +5,6 @@ using NUnit.Framework;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Core.Indexers.Omgwtfnzbs;
using NzbDrone.Core.Indexers.Wombles;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Test.Framework;
@@ -22,7 +21,6 @@ namespace NzbDrone.Core.Test.IndexerTests
_indexers.Add(Mocker.Resolve<Newznab>());
_indexers.Add(Mocker.Resolve<Omgwtfnzbs>());
_indexers.Add(Mocker.Resolve<Wombles>());
Mocker.SetConstant<IEnumerable<IIndexer>>(_indexers);
}
@@ -44,4 +42,4 @@ namespace NzbDrone.Core.Test.IndexerTests
AllStoredModels.Should().NotContain(c => c.Id == existingIndexers.Id);
}
}
}
}

View File

@@ -4,9 +4,7 @@ using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.KickassTorrents;
using NzbDrone.Core.Indexers.Nyaa;
using NzbDrone.Core.Indexers.Wombles;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
@@ -40,58 +38,6 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
};
}
[Test]
public void wombles_fetch_recent()
{
var indexer = Mocker.Resolve<Wombles>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = NullConfig.Instance
};
var result = indexer.FetchRecent();
ValidateResult(result);
}
[Test]
[ManualTest]
[Explicit]
public void kickass_fetch_recent()
{
var indexer = Mocker.Resolve<KickassTorrents>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = new KickassTorrentsSettings()
};
var result = indexer.FetchRecent();
ValidateTorrentResult(result, hasSize: true);
}
[Test]
[ManualTest]
[Explicit]
public void kickass_search_single()
{
var indexer = Mocker.Resolve<KickassTorrents>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = new KickassTorrentsSettings()
};
var result = indexer.Fetch(_singleSearchCriteria);
ValidateTorrentResult(result, hasSize: true, hasMagnet: true);
}
[Test]
public void nyaa_fetch_recent()
{

View File

@@ -1,173 +0,0 @@
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.KickassTorrents;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using System;
using System.Linq;
using FluentAssertions;
using System.Text.RegularExpressions;
namespace NzbDrone.Core.Test.IndexerTests.KickassTorrentsTests
{
[TestFixture]
public class KickassTorrentsFixture : CoreTest<KickassTorrents>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "Kickass Torrents",
Settings = new KickassTorrentsSettings() { VerifiedOnly = false }
};
}
[Test]
public void should_parse_recent_feed_from_KickassTorrents()
{
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo) releases.First();
torrentInfo.Title.Should().Be("Doctor Stranger.E03.140512.HDTV.H264.720p-iPOP.avi [CTRG]");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("http://torcache.net/torrent/208C4F7866612CC88BFEBC7C496FA72C2368D1C0.torrent?title=%5Bkickass.to%5Ddoctor.stranger.e03.140512.hdtv.h264.720p.ipop.avi.ctrg");
torrentInfo.InfoUrl.Should().Be("http://kickass.to/doctor-stranger-e03-140512-hdtv-h264-720p-ipop-avi-ctrg-t9100648.html");
torrentInfo.CommentUrl.Should().BeNullOrEmpty();
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("2014/05/12 16:16:49"));
torrentInfo.Size.Should().Be(1205364736);
torrentInfo.InfoHash.Should().Be("208C4F7866612CC88BFEBC7C496FA72C2368D1C0");
torrentInfo.MagnetUrl.Should().Be("magnet:?xt=urn:btih:208C4F7866612CC88BFEBC7C496FA72C2368D1C0&dn=doctor+stranger+e03+140512+hdtv+h264+720p+ipop+avi+ctrg&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce");
}
[Test]
public void should_return_empty_list_on_404()
{
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), new byte[0], System.Net.HttpStatusCode.NotFound));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(0);
ExceptionVerification.IgnoreWarns();
}
[Test]
public void should_not_return_unverified_releases_if_not_configured()
{
((KickassTorrentsSettings) Subject.Definition.Settings).VerifiedOnly = true;
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(4);
}
[Test]
public void should_set_seeders_to_null()
{
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed (but not the site), so set it to null if there aren't any peers.
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
recentFeed = recentFeed.Replace("<pubDate>Mon, 12 May 2014 16:16:49 +0000</pubDate>", string.Format("<pubDate>{0:R}</pubDate>", DateTime.UtcNow));
recentFeed = Regex.Replace(recentFeed, @"(seeds|peers)\>\d*", "$1>0");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo)releases.First();
torrentInfo.Peers.Should().NotHaveValue();
torrentInfo.Seeders.Should().NotHaveValue();
}
[Test]
public void should_not_set_seeders_to_null_if_has_peers()
{
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed (but not the site), so set it to null if there aren't any peers.
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
recentFeed = recentFeed.Replace("<pubDate>Mon, 12 May 2014 16:16:49 +0000</pubDate>", string.Format("<pubDate>{0:R}</pubDate>", DateTime.UtcNow));
recentFeed = Regex.Replace(recentFeed, @"(seeds)\>\d*", "$1>0");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo)releases.First();
torrentInfo.Peers.Should().Be(311);
torrentInfo.Seeders.Should().Be(0);
}
[Test]
public void should_not_set_seeders_to_null_if_older_than_12_hours()
{
// Atm, Kickass supplies 0 as seeders and leechers on the rss feed (but not the site), so set it to null if there aren't any peers.
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents.xml");
recentFeed = Regex.Replace(recentFeed, @"(seeds|peers)\>\d*", "$1>0");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = (TorrentInfo)releases.First();
torrentInfo.Peers.Should().Be(0);
torrentInfo.Seeders.Should().Be(0);
}
[Test]
public void should_handle_xml_with_html_accents()
{
var recentFeed = ReadAllText(@"Files/Indexers/KickassTorrents/KickassTorrents_accents.xml");
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.Is<HttpRequest>(v => v.Method == HttpMethod.GET)))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
}
}
}

View File

@@ -1,9 +1,12 @@
using FluentAssertions;
using System;
using System.Xml;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Newznab;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
{
@@ -64,5 +67,35 @@ namespace NzbDrone.Core.Test.IndexerTests.NewznabTests
caps.DefaultPageSize.Should().Be(100);
caps.MaxPageSize.Should().Be(100);
}
[Test]
public void should_throw_if_failed_to_get()
{
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Get(It.IsAny<HttpRequest>()))
.Throws<Exception>();
Assert.Throws<Exception>(() => Subject.GetCapabilities(_settings));
}
[Test]
public void should_throw_if_xml_invalid()
{
GivenCapsResponse(_caps.Replace("<limits", "<>"));
Assert.Throws<XmlException>(() => Subject.GetCapabilities(_settings));
}
[Test]
public void should_not_throw_on_xml_data_unexpected()
{
GivenCapsResponse(_caps.Replace("5030", "asdf"));
var result = Subject.GetCapabilities(_settings);
result.Should().NotBeNull();
ExceptionVerification.ExpectedErrors(1);
}
}
}

View File

@@ -173,6 +173,32 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
torrentInfo.Seeders.Should().NotHaveValue();
}
[Test]
public void should_parse_recent_feed_from_LimeTorrents()
{
GivenRecentFeedResponse("TorrentRss/LimeTorrents.xml");
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
releases.First().Should().BeOfType<TorrentInfo>();
var torrentInfo = releases.First() as TorrentInfo;
torrentInfo.Title.Should().Be("The Expanse 2x04 (720p-HDTV-x264-SVA)[VTV]");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("http://itorrents.org/torrent/51C578C9823DD58F6EEA287C368ED935843D63AB.torrent?title=The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]");
torrentInfo.InfoUrl.Should().BeNullOrEmpty();
torrentInfo.CommentUrl.Should().Be("http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html");
torrentInfo.Indexer.Should().Be(Subject.Definition.Name);
torrentInfo.PublishDate.Should().Be(DateTime.Parse("16 Feb 2017 05:24:26 +0300").ToUniversalTime());
torrentInfo.Size.Should().Be(880496711);
torrentInfo.InfoHash.Should().BeNull();
torrentInfo.MagnetUrl.Should().BeNull();
torrentInfo.Peers.Should().NotHaveValue();
torrentInfo.Seeders.Should().NotHaveValue();
}
[Test]
public void should_parse_recent_feed_from_AnimeTosho_without_size()
{
@@ -215,5 +241,22 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("http://storage.animetosho.org/torrents/4b58360143d59a55cbd922397a3eaa378165f3ff/DAYS%20-%2005%20%281280x720%20HEVC2%20AAC%29.torrent");
}
[Test]
public void should_parse_recent_feed_from_AlphaRatio()
{
GivenRecentFeedResponse("TorrentRss/AlphaRatio.xml");
var releases = Subject.FetchRecent();
releases.Should().HaveCount(2);
releases.Last().Should().BeOfType<TorrentInfo>();
var torrentInfo = releases.Last() as TorrentInfo;
torrentInfo.Title.Should().Be("TvHD 465860 465831 WWE.RAW.2016.11.28.720p.HDTV.x264-KYR");
torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent);
torrentInfo.DownloadUrl.Should().Be("https://alpharatio.cc/torrents.php?action=download&authkey=private_auth_key&torrent_pass=private_torrent_pass&id=465831");
}
}
}

View File

@@ -180,6 +180,46 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
});
}
[Test]
public void should_detect_rss_settings_for_LimeTorrents()
{
_indexerSettings.AllowZeroSize = true;
GivenRecentFeedResponse("TorrentRss/LimeTorrents.xml");
var settings = Subject.Detect(_indexerSettings);
settings.ShouldBeEquivalentTo(new TorrentRssIndexerParserSettings
{
UseEZTVFormat = false,
UseEnclosureUrl = true,
UseEnclosureLength = true,
ParseSizeInDescription = false,
ParseSeedersInDescription = false,
SizeElementName = null
});
}
[Test]
public void should_detect_rss_settings_for_AlphaRatio()
{
_indexerSettings.AllowZeroSize = true;
GivenRecentFeedResponse("TorrentRss/AlphaRatio.xml");
var settings = Subject.Detect(_indexerSettings);
settings.ShouldBeEquivalentTo(new TorrentRssIndexerParserSettings
{
UseEZTVFormat = false,
UseEnclosureUrl = false,
UseEnclosureLength = false,
ParseSizeInDescription = true,
ParseSeedersInDescription = false,
SizeElementName = null
});
}
[Test]
[Ignore("Cannot reliably reject unparseable titles")]
public void should_reject_rss_settings_for_AwesomeHD()
@@ -215,7 +255,6 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests
[TestCase("BitMeTv/BitMeTv.xml")]
[TestCase("Fanzub/fanzub.xml")]
[TestCase("KickassTorrents/KickassTorrents.xml")]
[TestCase("IPTorrents/IPTorrents.xml")]
[TestCase("Newznab/newznab_nzb_su.xml")]
[TestCase("Nyaa/Nyaa.xml")]

View File

@@ -1,59 +0,0 @@
using System;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Wombles;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Test.IndexerTests.WomblesTests
{
[TestFixture]
public class TorrentRssIndexerFixture : CoreTest<Wombles>
{
[SetUp]
public void Setup()
{
Subject.Definition = new IndexerDefinition()
{
Name = "Wombles",
Settings = new NullConfig(),
};
}
private void GivenRecentFeedResponse(string rssXmlFile)
{
var recentFeed = ReadAllText(@"Files/Indexers/" + rssXmlFile);
Mocker.GetMock<IHttpClient>()
.Setup(o => o.Execute(It.IsAny<HttpRequest>()))
.Returns<HttpRequest>(r => new HttpResponse(r, new HttpHeader(), recentFeed));
}
[Test]
public void should_parse_recent_feed_from_wombles()
{
GivenRecentFeedResponse("Wombles/wombles.xml");
var releases = Subject.FetchRecent();
releases.Should().HaveCount(5);
var releaseInfo = releases.First();
releaseInfo.Title.Should().Be("One.Child.S01E01.720p.HDTV.x264-TLA");
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
releaseInfo.DownloadUrl.Should().Be("http://indexer.local/nzb/bb4/One.Child.S01E01.720p.HDTV.x264-TLA.nzb");
releaseInfo.InfoUrl.Should().BeNullOrEmpty();
releaseInfo.CommentUrl.Should().BeNullOrEmpty();
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2016-02-17 23:03:52 +0000").ToUniversalTime());
releaseInfo.Size.Should().Be(956*1024*1024);
}
}
}

View File

@@ -5,6 +5,7 @@ using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Test.Framework;
@@ -17,28 +18,50 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
public class ScanFixture : CoreTest<DiskScanService>
{
private Series _series;
private string _rootFolder;
private string _otherSeriesFolder;
[SetUp]
public void Setup()
{
_rootFolder = @"C:\Test\TV".AsOsAgnostic();
_otherSeriesFolder = @"C:\Test\TV\OtherSeries".AsOsAgnostic();
var seriesFolder = @"C:\Test\TV\Series".AsOsAgnostic();
_series = Builder<Series>.CreateNew()
.With(s => s.Path = @"C:\Test\TV\Series".AsOsAgnostic())
.With(s => s.Path = seriesFolder)
.Build();
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(It.IsAny<string>()))
.Returns(false);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetParentFolder(It.IsAny<string>()))
.Returns((string path) => Directory.GetParent(path).FullName);
}
private void GivenParentFolderExists()
private void GivenRootFolder(params string[] subfolders)
{
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(It.IsAny<string>()))
.Setup(s => s.FolderExists(_rootFolder))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(It.IsAny<string>()))
.Returns(new string[] { @"C:\Test\TV\Series2".AsOsAgnostic() });
.Setup(s => s.GetDirectories(_rootFolder))
.Returns(subfolders);
foreach (var folder in subfolders)
{
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(folder))
.Returns(true);
}
}
private void GivenSeriesFolder()
{
GivenRootFolder(_series.Path);
}
private void GivenFiles(IEnumerable<string> files)
@@ -49,39 +72,124 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
}
[Test]
public void should_not_scan_if_series_root_folder_does_not_exist()
{
public void should_not_scan_if_root_folder_does_not_exist()
{
Subject.Scan(_series);
ExceptionVerification.ExpectedWarns(1);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.FolderExists(_series.Path), Times.Never());
Mocker.GetMock<IMediaFileTableCleanupService>()
.Verify(v => v.Clean(It.IsAny<Series>(), It.IsAny<List<string>>()), Times.Never());
.Verify(v => v.Clean(It.IsAny<Series>(), It.IsAny<List<string>>()), Times.Never());
}
[Test]
public void should_not_scan_if_series_root_folder_is_empty()
{
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(It.IsAny<string>()))
.Returns(new string[0]);
GivenRootFolder();
Subject.Scan(_series);
ExceptionVerification.ExpectedWarns(1);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.FolderExists(_series.Path), Times.Never());
Mocker.GetMock<IMediaFileTableCleanupService>()
.Verify(v => v.Clean(It.IsAny<Series>(), new List<string>()), Times.Never());
.Verify(v => v.Clean(It.IsAny<Series>(), It.IsAny<List<string>>()), Times.Never());
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.IsAny<List<string>>(), _series), Times.Never());
}
[Test]
public void should_create_if_series_folder_does_not_exist_but_create_folder_enabled()
{
GivenRootFolder(_otherSeriesFolder);
Mocker.GetMock<IConfigService>()
.Setup(s => s.CreateEmptySeriesFolders)
.Returns(true);
Subject.Scan(_series);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.CreateFolder(_series.Path), Times.Once());
}
[Test]
public void should_not_create_if_series_folder_does_not_exist_and_create_folder_disabled()
{
GivenRootFolder(_otherSeriesFolder);
Mocker.GetMock<IConfigService>()
.Setup(s => s.CreateEmptySeriesFolders)
.Returns(false);
Subject.Scan(_series);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.CreateFolder(_series.Path), Times.Never());
}
[Test]
public void should_clean_but_not_import_if_series_folder_does_not_exist()
{
GivenRootFolder(_otherSeriesFolder);
Subject.Scan(_series);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.FolderExists(_series.Path), Times.Once());
Mocker.GetMock<IMediaFileTableCleanupService>()
.Verify(v => v.Clean(It.IsAny<Series>(), It.IsAny<List<string>>()), Times.Once());
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.IsAny<List<string>>(), _series), Times.Never());
}
[Test]
public void should_clean_but_not_import_if_series_folder_does_not_exist_and_create_folder_enabled()
{
GivenRootFolder(_otherSeriesFolder);
Mocker.GetMock<IConfigService>()
.Setup(s => s.CreateEmptySeriesFolders)
.Returns(true);
Subject.Scan(_series);
Mocker.GetMock<IMediaFileTableCleanupService>()
.Verify(v => v.Clean(It.IsAny<Series>(), It.IsAny<List<string>>()), Times.Once());
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.IsAny<List<string>>(), _series), Times.Never());
}
[Test]
public void should_find_files_at_root_of_series_folder()
{
GivenSeriesFolder();
GivenFiles(new List<string>
{
Path.Combine(_series.Path, "file1.mkv").AsOsAgnostic(),
Path.Combine(_series.Path, "s01e01.mkv").AsOsAgnostic()
});
Subject.Scan(_series);
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _series), Times.Once());
}
[Test]
public void should_not_scan_extras_subfolder()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{
@@ -94,6 +202,9 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
Subject.Scan(_series);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetFiles(It.IsAny<string>(), It.IsAny<SearchOption>()), Times.Once());
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series), Times.Once());
}
@@ -101,7 +212,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_scan_AppleDouble_subfolder()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{
@@ -119,9 +230,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_scan_extras_series_and_subfolders()
{
GivenParentFolderExists();
_series.Path = @"C:\Test\TV\Extras".AsOsAgnostic();
GivenSeriesFolder();
GivenFiles(new List<string>
{
Path.Combine(_series.Path, "Extras", "file1.mkv").AsOsAgnostic(),
@@ -141,7 +253,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_scan_subfolders_that_start_with_period()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{
@@ -160,7 +272,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_scan_subfolder_of_season_folder_that_starts_with_a_period()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{
@@ -180,7 +292,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_scan_Synology_eaDir()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{
@@ -197,7 +309,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_not_scan_thumb_folder()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{
@@ -214,9 +326,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
[Test]
public void should_scan_dotHack_folder()
{
GivenParentFolderExists();
_series.Path = @"C:\Test\TV\.hack".AsOsAgnostic();
GivenSeriesFolder();
GivenFiles(new List<string>
{
Path.Combine(_series.Path, "Season 1", "file1.mkv").AsOsAgnostic(),
@@ -229,27 +342,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _series), Times.Once());
}
[Test]
public void should_find_files_at_root_of_series_folder()
{
GivenParentFolderExists();
GivenFiles(new List<string>
{
Path.Combine(_series.Path, "file1.mkv").AsOsAgnostic(),
Path.Combine(_series.Path, "s01e01.mkv").AsOsAgnostic()
});
Subject.Scan(_series);
Mocker.GetMock<IMakeImportDecision>()
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _series), Times.Once());
}
[Test]
public void should_exclude_osx_metadata_files()
{
GivenParentFolderExists();
GivenSeriesFolder();
GivenFiles(new List<string>
{

Some files were not shown because too many files have changed in this diff Show More