1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-21 16:54:30 -04:00

Compare commits

..

92 Commits

Author SHA1 Message Date
Taloth Saldono
0cffd851f3 Fixed: Deluge 1.3.14 API support due to changed json-rpc checks.
fixes #1738
2017-03-06 20:32:09 +01:00
Marcelo Castagna
270bc9b955 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-06 20:31:42 +01: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
Keivan Beigi
2e36d35815 Added app.manifest to indicate proper windows 10 support 2017-01-06 16:02:57 -08:00
Keivan Beigi
ed2e4d0f1d Sentry will now back-off if it's API key is revoked. 2017-01-06 11:55:54 -08:00
Keivan Beigi
0bdc137093 Smaller sentry payload, send machine name as user name 2017-01-05 17:43:24 -08:00
Keivan Beigi
cd7e208efa Revert "Use line number instead of message for sentry fingerprint"
This reverts commit 5f339c0a92e3255890fb63dfa3e650852a81d60f.

# Conflicts:
#	src/NzbDrone.Common/Instrumentation/Sentry/SentryTarget.cs
2017-01-05 17:43:24 -08:00
Keivan Beigi
73840dcacc The great logger.Error cleanup! 2017-01-05 17:43:24 -08:00
Keivan Beigi
e45d4f60a4 Moved Fatal logging to use nlog patterns 2017-01-05 17:43:24 -08:00
Keivan Beigi
782efcfaf1 Added a one hour debounce of reporting the same errors to sentry 2017-01-05 17:43:24 -08:00
Keivan Beigi
76a7d4f866 Use line number instead of message for sentry fingerprint 2017-01-05 17:43:24 -08:00
Keivan Beigi
d61976251e Apparently RemoveTarget doesn't do what you expect it to do. 2017-01-05 10:46:16 -08:00
Keivan Beigi
2487e8ed49 Don't report errors that don't have exceptions 2017-01-05 10:25:50 -08:00
Keivan Beigi
54bc642476 Fixed: OS Version detection shouldn't break user agents. Fixes #1611 2017-01-05 10:25:05 -08:00
Keivan Beigi
6577b0a721 Don't include null in sentry fingerprint if even has no exception 2017-01-04 23:28:51 -08:00
Keivan Beigi
bcd67dee5e Added fingerprint to sentry events to allow better grouping 2017-01-04 20:01:43 -08:00
Keivan Beigi
e6705db743 Added platform version error handling 2017-01-04 19:15:47 -08:00
Keivan Beigi
dd7fdd8ace Disable Sentry Reporting based on analytics flag 2017-01-04 17:56:29 -08:00
Keivan Beigi
a1f112e62f Added branch name to Assembly Info 2017-01-04 14:20:13 -08:00
Keivan Beigi
053c730799 Added Sentry error reporting 2017-01-04 14:19:53 -08:00
Keivan Beigi
61579cfb7e Consider /buildAgent/ to be a none production startup path 2017-01-04 14:19:50 -08:00
Keivan Beigi
92d706a10d Updated bindingRedirect for Newtonsoft.Json 2017-01-04 14:18:38 -08:00
Keivan Beigi
6ae5829439 Removed duplicated code from ContainerBuilders 2017-01-04 14:18:37 -08:00
Keivan Beigi
8252a2a60f RIP 2017-01-04 00:19:32 -08:00
Keivan Beigi
009dc14805 Added Windows Server detection logic 2017-01-03 18:56:28 -08:00
Keivan Beigi
e0ff25d5be New: switched nyaa to HTTPS 2017-01-03 18:37:46 -08:00
Keivan Beigi
ad7d571b24 New: Better platform detection specifically for Non-Windows Systems 2017-01-03 18:37:23 -08:00
Keivan Beigi
598b5322b7 Fixed linux build 2017-01-03 18:31:48 -08:00
Keivan Beigi
76505bdaa1 Added Rider dir to git ignore. 2017-01-03 18:30:21 -08:00
Keivan Beigi
d64d35361c Revert "Upgraded Moq" (Mono compatibility)
This reverts commit 3140d5d4b0.
2017-01-03 10:25:01 -08:00
Mark McDowall
d5ef451bb4 Fixed: Parsing of 2017x123 episode format 2017-01-02 11:46:25 -08:00
Keivan Beigi
3140d5d4b0 Upgraded Moq 2016-12-28 22:41:48 -08:00
Keivan Beigi
fdb5ccdae1 Updated Newtonsoft.Json from 6.0.6 to 9.0.1 2016-12-28 22:41:47 -08:00
Keivan Beigi
a2ce435239 Upgraded Nlog, NCrunch 2016-12-28 22:41:46 -08:00
Keivan Beigi
a34e69b35b Notification API Cleanup 2016-12-27 23:52:20 -08:00
1262 changed files with 18764 additions and 48859 deletions

View File

@@ -1,12 +1,5 @@
**Description:**
Provide a description of the feature request or bug here, the more details the better.
Please also try to include the following if you are reporting a bug
**Radarr Version:**
**Logs:**
Please use the search bar and make sure you are not submitting an already submitted issue.
Visit our [Discord server](https://discord.gg/NWYch8M) for support or longer discussions.
Provide a description of the feature request or bug, the more details the better.
Please use https://forums.sonarr.tv/ for support or other questions. (When in doubt, use the forums)

View File

@@ -2,11 +2,13 @@
YES | NO
#### Description
A few sentences describing the overall goals of the pull request's commits.
#### Todos
- [ ] Tests
- [ ] Documentation
#### Issues Fixed or Closed by this PR
* #
*

29
.gitignore vendored
View File

@@ -101,21 +101,16 @@ App_Data/*.ldf
_NCrunch_*
_TeamCity*
# Radarr
Backups/
logs/
MediaCover/
UpdateLogs/
xdg/
# Sonarr
config.xml
logs.db*
nzbdrone.db*
nzbdrone.pid
nzbdrone.log*txt
UpdateLogs/
*workspace.xml
*.test-cache
*.userprefs
*/test-results/*
src/UI/.idea/*
*log.txt
node_modules/
_output*
_rawPackage/
@@ -127,26 +122,16 @@ setup/Output/
UI.Phantom/
# VS outout folders
#VS outout folders
bin
obj
output/*
# Packages
Radarr_*/
Radarr_*.zip
Radarr_*.gz
# macOS metadata files
#OS X metadata files
._*
.DS_Store
_start
_temp_*/**/*
# Windows thumbnail cache files
Thumbs.db
# AppVeyor
/tools-cake/
/_artifacts/
src/.idea/

View File

@@ -1,16 +0,0 @@
language: csharp
solution: src/NzbDrone.sln
addons:
apt:
packages:
- nodejs
# - npm apparently not needed anymore.
script:
- ./build.sh
- chmod +x test.sh
# - ./test.sh Linux Unit Takes far too long, maybe even crashes travis :/
after_success:
- chmod +x package.sh
- ./package.sh
notifications:
- webhooks: https://discordapp.com/api/webhooks/266910310219251712/V-QvCcnYkg3O8PMevcAJOJyCgrYkZQoF2pupLDGbaISNUECmYPd6LRwl3avKHsPyfgWP

BIN
7za.dll

Binary file not shown.

BIN
7za.exe

Binary file not shown.

BIN
7zxa.dll

Binary file not shown.

4
CLA.md
View File

@@ -1,6 +1,6 @@
# Radarr Individual Contributor License Agreement #
# Sonarr Individual Contributor License Agreement #
Thank you for your interest in contributing to Radarr ("We" or "Us").
Thank you for your interest in contributing to Sonarr ("We" or "Us").
This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please complete the form below. This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us.
## 1. Definitions ##

View File

@@ -1,6 +1,6 @@
# How to Contribute #
We're always looking for people to help make Radarr even better, there are a number of ways to contribute.
We're always looking for people to help make Sonarr even better, there are a number of ways to contribute.
## Documentation ##
Setup guides, FAQ, the more information we have on the wiki the better.
@@ -15,7 +15,7 @@ Setup guides, FAQ, the more information we have on the wiki the better.
### Getting started ###
1. Fork Radarr
1. Fork Sonarr
2. Clone (develop branch) *you may need pull in submodules separately if you client doesn't clone them automatically (CurlSharp)*
3. Run `npm install`
4. Run `npm start` - Used to compile the UI components and copy them.
@@ -24,8 +24,8 @@ Setup guides, FAQ, the more information we have on the wiki the better.
5. Compile in Visual Studio
### Contributing Code ###
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Radarr/Radarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Radarr's develop branch, don't merge
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Sonarr/Sonarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Sonarr's develop branch, don't merge
- Make meaningful commits, or squash them
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
- Reach out to us on the forums or on IRC if you have any questions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 B

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 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: 17 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

240
Logo/Sonarr.svg Normal file
View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="218px"
height="218px" viewBox="0 0 218 218" enable-background="new 0 0 218 218" xml:space="preserve">
<symbol id="hex_grid" viewBox="-114.25 -98.617 228.55 197.233">
<path fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#989898" stroke-width="0.5" stroke-linecap="square" stroke-miterlimit="1" d="
M72.15,90.3l4.7-2.7l4.65,2.7v5.4l-4.65,2.7l-4.7-2.7V90.3z M62.85,95.7l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7V95.7l4.65,2.7
l4.65-2.7 M62.85,90.3l4.65-2.7l4.65,2.7 M62.85,79.55v-5.4l4.65-2.7l4.65,2.7v5.4L67.5,82.2L62.85,79.55L58.2,82.2l-4.65-2.65
M72.15,74.15l4.7-2.7l4.65,2.7v5.4l-4.65,2.65l-4.7-2.65 M76.85,87.6v-5.4 M67.5,87.6v-5.4 M81.5,95.7l4.65,2.7l4.65-2.7l4.65,2.7
l4.65-2.7l4.65,2.7l4.65-2.7v-5.4l4.65-2.7v-5.4l-4.65-2.65v-5.4l4.65-2.7v-5.4l-4.65-2.7v-5.4l4.65-2.7v-5.4l-4.65-2.65v-5.4
l4.65-2.7v-5.4L109.4,31v-5.4l4.65-2.7v-5.4l-4.65-2.65v-5.4l4.65-2.7v-5.4l-4.65-2.7v-5.4l4.65-2.7v-5.4l-4.65-2.65v-5.4l4.65-2.7
V-31l-4.65-2.7v-5.4l4.65-2.7v-5.4l-4.65-2.65v-5.4l4.65-2.7v-5.4l-4.65-2.7v-5.4l4.65-2.7v-5.4l-4.65-2.65v-5.4l4.65-2.7v-5.4
l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.7-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7
l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.7-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7L7-98.4l-4.65,2.7l-4.65-2.7
l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.7-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7
l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.7-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7l-4.65-2.7l-4.65,2.7v5.4l-4.65,2.7
v5.4l4.65,2.65v5.4l-4.65,2.7v5.4l4.65,2.7v5.4l-4.65,2.7v5.4l4.65,2.65v5.4l-4.65,2.7v5.4l4.65,2.7v5.4l-4.65,2.7v5.4l4.65,2.65
v5.4l-4.65,2.7v5.4l4.65,2.7v5.4l-4.65,2.7v5.4l4.65,2.65v5.4l-4.65,2.7V31l4.65,2.7v5.4l-4.65,2.7v5.4l4.65,2.65v5.4l-4.65,2.7
v5.4l4.65,2.7v5.4l-4.65,2.7v5.4l4.65,2.65v5.4l-4.65,2.7v5.4l4.65,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.7,2.7
l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.7,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7
l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7L7,95.7l4.65,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.7,2.7l4.65-2.7l4.65,2.7l4.65-2.7l4.65,2.7
l4.65-2.7 M44.25,95.7v-5.4l4.65-2.7l4.65,2.7 M44.25,79.55v-5.4l4.65-2.7l4.65,2.7v5.4L48.9,82.2L44.25,79.55L39.6,82.2
l-4.65-2.65 M58.2,87.6v-5.4 M48.9,87.6v-5.4 M53.55,63.35v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7L53.55,63.35l-4.65,2.7l-4.65-2.7
v-5.4l4.65-2.7l4.65,2.7 M62.85,74.15l-4.65-2.7v-5.4 M53.55,74.15l4.65-2.7 M48.9,71.45v-5.4 M48.9,55.25v-5.4l4.65-2.65
l4.65,2.65v5.4 M67.5,71.45v-5.4l4.65-2.7l4.7,2.7v5.4 M67.5,66.05l-4.65-2.7 M58.2,49.85l4.65-2.65l4.65,2.65v5.4l-4.65,2.7
M72.15,63.35v-5.4l4.7-2.7l4.65,2.7v5.4l-4.65,2.7 M76.85,55.25v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M67.5,55.25l4.65,2.7
M34.95,95.7v-5.4l4.65-2.7l4.65,2.7 M16.3,95.7v-5.4l4.65-2.7l4.65,2.7v5.4 M25.6,90.3l4.7-2.7l4.65,2.7 M25.6,79.55v-5.4l4.7-2.7
l4.65,2.7v5.4L30.3,82.2L25.6,79.55l-4.65,2.65l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M20.95,87.6v-5.4 M39.6,87.6v-5.4 M30.3,87.6
v-5.4 M7,95.7v-5.4l4.65-2.7l4.65,2.7 M-2.3,95.7v-5.4l4.65-2.7L7,90.3 M2.35,82.2l-4.65-2.65v-5.4l4.65-2.7L7,74.15v5.4L2.35,82.2
z M16.3,79.55l-4.65,2.65L7,79.55 M2.35,87.6v-5.4 M11.65,87.6v-5.4 M16.3,74.15l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M2.35,71.45
v-5.4L7,63.35l4.65,2.7 M2.35,49.85L7,47.2l4.65,2.65v5.4L7,57.95l-4.65-2.7V49.85L-2.3,47.2v-5.4l4.65-2.7L7,41.8v5.4
M11.65,55.25l4.65,2.7v5.4 M7,74.15l4.65-2.7 M7,57.95v5.4 M30.3,71.45v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7 M16.3,57.95
l4.65-2.7l4.65,2.7v5.4l-4.65,2.7 M30.3,66.05l-4.7-2.7 M30.3,49.85l4.65-2.65l4.65,2.65v5.4l-4.65,2.7l-4.65-2.7V49.85l-4.7-2.65
v-5.4l-4.65-2.7v-5.4L25.6,31l4.7,2.7v5.4l-4.7,2.7 M11.65,49.85l4.65-2.65l4.65,2.65v5.4 M25.6,57.95l4.7-2.7 M34.95,57.95v5.4
M34.95,47.2v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65 M25.6,31v-5.4l4.7-2.7l4.65,2.7V31l-4.65,2.7 M34.95,25.6l4.65-2.7l4.65,2.7
V31l-4.65,2.7L34.95,31 M30.3,39.1l4.65,2.7 M39.6,39.1v-5.4 M20.95,39.1l-4.65,2.7l-4.65-2.7v-5.4L16.3,31l4.65,2.7 M16.3,41.8
v5.4 M2.35,33.7L-2.3,31v-5.4l4.65-2.7L7,25.6V31L2.35,33.7z M7,25.6l4.65-2.7l4.65,2.7V31 M2.35,39.1v-5.4 M11.65,33.7L7,31
M7,41.8l4.65-2.7 M11.65,17.5L7,14.85v-5.4l4.65-2.7l4.65,2.7v5.4L11.65,17.5z M11.65,22.9v-5.4 M2.35,22.9v-5.4L7,14.85 M7,9.45
l-4.65-2.7v-5.4L7-1.35l4.65,2.7v5.4 M34.95,14.85v-5.4l4.65-2.7l4.65,2.7v5.4L39.6,17.5L34.95,14.85z M39.6,22.9v-5.4 M25.6,25.6
l-4.65-2.7v-5.4l4.65-2.65l4.7,2.65v5.4 M16.3,9.45l4.65-2.7l4.65,2.7v5.4 M34.95,9.45l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4
M11.65,1.35l4.65-2.7l4.65,2.7v5.4 M25.6,9.45l4.7-2.7 M30.3,17.5l4.65-2.65 M16.3,25.6l4.65-2.7 M20.95,17.5l-4.65-2.65
M76.85,49.85l-4.7-2.65v-5.4l4.7-2.7l4.65,2.7v5.4 M62.85,47.2v-5.4l4.65-2.7l4.65,2.7 M62.85,25.6l4.65-2.7l4.65,2.7V31
l-4.65,2.7L62.85,31V25.6l-4.65-2.7v-5.4 M72.15,25.6l4.7-2.7l4.65,2.7V31l-4.65,2.7l-4.7-2.7 M76.85,39.1v-5.4 M67.5,39.1v-5.4
M53.55,47.2v-5.4l4.65-2.7l4.65,2.7 M44.25,41.8l4.65-2.7l4.65,2.7 M44.25,25.6l4.65-2.7l4.65,2.7V31l-4.65,2.7L44.25,31
M62.85,31l-4.65,2.7L53.55,31 M58.2,39.1v-5.4 M48.9,39.1v-5.4 M53.55,14.85v-5.4l4.65-2.7l4.65,2.7v5.4L58.2,17.5L53.55,14.85
L48.9,17.5l-4.65-2.65 M48.9,22.9v-5.4 M53.55,9.45l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M44.25,9.45l4.65-2.7 M76.85,22.9v-5.4
l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M76.85,17.5l-4.7-2.65v-5.4l4.7-2.7l4.65,2.7v5.4 M67.5,22.9v-5.4l4.65-2.65 M67.5,17.5
l-4.65-2.65 M72.15,9.45l-4.65-2.7v-5.4l4.65-2.7l4.7,2.7v5.4 M62.85,9.45l4.65-2.7 M53.55,25.6l4.65-2.7 M44.25,63.35l-4.65,2.7
M39.6,55.25l4.65,2.7 M39.6,71.45l4.65,2.7 M67.5,49.85l4.65-2.65 M48.9,49.85l-4.65-2.65 M25.6,47.2l-4.65,2.65 M104.75,87.6
l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65V87.6l4.65,2.7 M109.4,79.55l-4.65,2.65 M100.1,95.7v-5.4 M81.5,90.3l4.65-2.7
l4.65,2.7v5.4 M81.5,74.15l4.65-2.7l4.65,2.7v5.4l-4.65,2.65l-4.65-2.65 M90.8,79.55l4.65,2.65 M86.15,87.6v-5.4 M90.8,90.3
l4.65-2.7 M95.45,71.45v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7L95.45,71.45l-4.65,2.7 M86.15,55.25l4.65,2.7v5.4l-4.65,2.7
l-4.65-2.7 M86.15,71.45v-5.4 M95.45,55.25v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7L95.45,55.25l-4.65,2.7 M100.1,63.35v-5.4
M90.8,63.35l4.65,2.7 M109.4,63.35l-4.65,2.7 M104.75,71.45l4.65,2.7 M104.75,55.25l4.65,2.7 M100.1,79.55v-5.4 M100.1,47.2v-5.4
l4.65-2.7l4.65,2.7 M100.1,41.8l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M109.4,31l-4.65,2.7 M81.5,41.8l4.65-2.7l4.65,2.7v5.4
l-4.65,2.65 M86.15,22.9l4.65,2.7V31l-4.65,2.7L81.5,31 M100.1,31v-5.4l4.65-2.7l4.65,2.7 M90.8,31l4.65,2.7 M86.15,39.1v-5.4
M90.8,41.8l4.65-2.7 M86.15,17.5l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M90.8,14.85v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65
M81.5,9.45l4.65-2.7l4.65,2.7 M86.15,6.75v-5.4l4.65-2.7l4.65,2.7v5.4 M100.1,14.85l4.65,2.65v5.4 M109.4,14.85l-4.65,2.65
M100.1,9.45l4.65-2.7l4.65,2.7 M95.45,1.35l4.65-2.7l4.65,2.7v5.4 M95.45,22.9l4.65,2.7 M109.4,47.2l-4.65,2.65 M90.8,47.2
l4.65,2.65 M104.75-9.45l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65V-9.45l4.65,2.7 M109.4-17.5l-4.65,2.65 M100.1-1.35v-5.4
M90.8-1.35v-5.4l4.65-2.7 M81.5-6.75l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4L81.5-6.75v5.4l-4.65,2.7 M90.8-6.75l-4.65-2.7
M95.45-14.85L90.8-17.5v-5.4l4.65-2.7l4.65,2.7v5.4 M76.85-14.85l-4.7-2.65v-5.4l4.7-2.7l4.65,2.7v5.4 M86.15-14.85l4.65-2.65
M95.45-31l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4L95.45-31z M95.45-25.6V-31 M90.8-22.9l-4.65-2.7V-31l4.65-2.7 M86.15-31
l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M86.15-41.8v-5.4l4.65-2.65l4.65,2.65v5.4 M100.1-33.7l4.65,2.7v5.4l-4.65,2.7 M109.4-33.7
l-4.65,2.7 M95.45-47.2l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M104.75-41.8l4.65,2.7 M81.5-22.9l4.65-2.7 M104.75-25.6l4.65,2.7
M100.1-49.85v-5.4l4.65-2.7l4.65,2.7 M109.4-66.05l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M104.75-63.35v5.4 M100.1-55.25
l-4.65-2.7v-5.4l4.65-2.7 M86.15-47.2l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4 M86.15-74.15l4.65,2.7v5.4l-4.65,2.7l-4.65-2.7v-5.4
L86.15-74.15v-5.4l4.65-2.65l4.65,2.65 M90.8-71.45l4.65-2.7l4.65,2.7 M95.45-63.35l-4.65-2.7 M90.8-55.25l4.65-2.7 M86.15-57.95
v-5.4 M95.45-74.15v-5.4l4.65-2.65l4.65,2.65v5.4 M81.5-71.45l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65 M81.5-82.2v-5.4l4.65-2.7
l4.65,2.7v5.4 M86.15-90.3v-5.4 M104.75-95.7v5.4l-4.65,2.7l-4.65-2.7v-5.4 M100.1-82.2v-5.4 M95.45-90.3l-4.65,2.7 M109.4-82.2
l-4.65,2.65 M104.75-90.3l4.65,2.7 M109.4-49.85l-4.65,2.65 M72.15-1.35v-5.4l4.7-2.7 M67.5,1.35l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7
M72.15-17.5l-4.65,2.65l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M67.5-14.85v5.4 M53.55-1.35v-5.4l4.65-2.7l4.65,2.7 M48.9,1.35
l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M44.25-22.9l4.65-2.7l4.65,2.7v5.4l-4.65,2.65l-4.65-2.65V-22.9l-4.65-2.7V-31 M53.55-17.5
l4.65,2.65v5.4 M48.9-9.45v-5.4 M53.55-33.7v-5.4l4.65-2.7l4.65,2.7v5.4L58.2-31L53.55-33.7z M62.85-22.9l-4.65-2.7V-31 M48.9-25.6
V-31l4.65-2.7 M48.9-31l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M48.9-41.8v-5.4l4.65-2.65l4.65,2.65v5.4 M76.85-25.6V-31l4.65-2.7
M76.85-31l-4.7-2.7v-5.4l4.7-2.7l4.65,2.7 M62.85-33.7L67.5-31v5.4 M72.15-39.1l-4.65-2.7v-5.4l4.65-2.65l4.7,2.65v5.4
M62.85-39.1l4.65-2.7 M72.15-33.7L67.5-31 M53.55-22.9l4.65-2.7 M58.2-14.85l4.65-2.65 M30.3,1.35l-4.7-2.7v-5.4l4.7-2.7l4.65,2.7
v5.4 M30.3-9.45v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M16.3-1.35v-5.4l4.65-2.7l4.65,2.7 M30.3-14.85l-4.7-2.65v-5.4l4.7-2.7
l4.65,2.7v5.4 M25.6-17.5l-4.65,2.65L16.3-17.5v-5.4l4.65-2.7l4.65,2.7 M20.95-14.85v5.4 M16.3-6.75l-4.65-2.7v-5.4l4.65-2.65
M2.35,1.35l-4.65-2.7v-5.4l4.65-2.7L7-6.75v5.4 M7-17.5l-4.65,2.65L-2.3-17.5v-5.4l4.65-2.7L7-22.9V-17.5l4.65,2.65 M11.65-9.45
L7-6.75 M2.35-9.45v-5.4 M11.65-31L7-33.7v-5.4l4.65-2.7l4.65,2.7v5.4L11.65-31z M16.3-22.9l-4.65-2.7V-31 M2.35-25.6V-31L7-33.7
M7-39.1l-4.65-2.7v-5.4L7-49.85l4.65,2.65v5.4 M44.25-33.7L39.6-31l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M20.95-25.6V-31l4.65-2.7
l4.7,2.7v5.4 M20.95-47.2l4.65-2.65l4.7,2.65v5.4l-4.7,2.7l-4.65-2.7V-47.2l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M30.3-47.2
l4.65-2.65l4.65,2.65v5.4 M30.3-41.8l4.65,2.7 M25.6-33.7v-5.4 M34.95-33.7L30.3-31 M34.95-22.9l4.65-2.7 M20.95-31l-4.65-2.7
M16.3-39.1l4.65-2.7 M7-22.9l4.65-2.7 M34.95-55.25l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4L34.95-55.25v5.4 M25.6-49.85v-5.4
l4.7-2.7 M30.3-63.35l-4.7-2.7v-5.4l4.7-2.7l4.65,2.7v5.4 M25.6-66.05l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M30.3-74.15
v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M20.95-63.35v5.4 M7-49.85v-5.4l4.65-2.7l4.65,2.7 M2.35-47.2l-4.65-2.65v-5.4l4.65-2.7
L7-55.25 M2.35-63.35l-4.65-2.7v-5.4l4.65-2.7L7-71.45v5.4L2.35-63.35z M16.3-71.45l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4
M11.65-57.95v-5.4l4.65-2.7 M2.35-57.95v-5.4 M7-66.05l4.65,2.7 M11.65-74.15L7-71.45 M2.35-74.15v-5.4L7-82.2l4.65,2.65
M11.65-95.7v5.4L7-87.6l-4.65-2.7v-5.4 M20.95-95.7v5.4l-4.65,2.7l-4.65-2.7 M7-87.6v5.4 M16.3-87.6v5.4 M20.95-90.3l4.65,2.7v5.4
l-4.65,2.65 M30.3-79.55l-4.7-2.65 M30.3-95.7v5.4l-4.7,2.7 M48.9-95.7v5.4l-4.65,2.7l-4.65-2.7v-5.4 M34.95-82.2v-5.4l4.65-2.7
M30.3-90.3l4.65,2.7 M72.15-49.85v-5.4l4.7-2.7l4.65,2.7 M67.5-47.2l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M67.5-74.15l4.65,2.7v5.4
l-4.65,2.7l-4.65-2.7v-5.4L67.5-74.15v-5.4l4.65-2.65l4.7,2.65 M81.5-66.05l-4.65,2.7l-4.7-2.7 M72.15-71.45l4.7-2.7 M76.85-63.35
v5.4 M67.5-57.95v-5.4 M53.55-49.85v-5.4l4.65-2.7l4.65,2.7 M48.9-47.2l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M44.25-66.05v-5.4
l4.65-2.7l4.65,2.7v5.4l-4.65,2.7L44.25-66.05l-4.65,2.7 M62.85-66.05l-4.65,2.7l-4.65-2.7 M53.55-71.45l4.65-2.7l4.65,2.7
M58.2-57.95v-5.4 M48.9-57.95v-5.4 M48.9-74.15v-5.4l4.65-2.65l4.65,2.65v5.4 M48.9-79.55l-4.65-2.65v-5.4 M58.2-95.7v5.4
l-4.65,2.7l-4.65-2.7 M53.55-87.6v5.4 M58.2-79.55l4.65-2.65l4.65,2.65 M62.85-82.2v-5.4l4.65-2.7l4.65,2.7v5.4 M67.5-90.3v-5.4
M76.85-95.7v5.4l-4.7,2.7 M58.2-90.3l4.65,2.7 M44.25-17.5l-4.65,2.65 M39.6-9.45l4.65,2.7 M39.6-74.15l4.65,2.7 M39.6-57.95
l4.65,2.7 M44.25-49.85L39.6-47.2 M62.85-49.85L58.2-47.2 M16.3-49.85l-4.65,2.65 M44.25-82.2l-4.65,2.65 M76.85-90.3l4.65,2.7
M81.5-49.85l-4.65,2.65 M86.15,1.35l-4.65-2.7 M44.25-1.35l-4.65,2.7 M62.85-1.35l-4.65,2.7 M109.4-1.35l-4.65,2.7 M25.6-1.35
l-4.65,2.7 M-95.4,95.7v-5.4l4.65-2.7l4.65,2.7v5.4 M-86.1,90.3l4.7-2.7l4.65,2.7v5.4 M-104.7,95.7v-5.4l4.65-2.7l4.65,2.7
M-100.05,82.2l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4L-100.05,82.2z M-95.4,74.15l4.65-2.7l4.65,2.7v5.4l-4.65,2.65l-4.65-2.65
M-86.1,74.15l4.7-2.7l4.65,2.7v5.4l-4.65,2.65l-4.7-2.65 M-100.05,87.6v-5.4 M-90.75,87.6v-5.4 M-81.4,87.6v-5.4 M-109.35,87.6
l4.65,2.7 M-104.7,79.55l-4.65,2.65 M-109.35,55.25l4.65,2.7v5.4l-4.65,2.7 M-109.35,71.45l4.65,2.7 M-90.75,66.05l-4.65-2.7v-5.4
l4.65-2.7l4.65,2.7v5.4L-90.75,66.05v5.4 M-86.1,57.95l4.7-2.7l4.65,2.7v5.4l-4.65,2.7l-4.7-2.7 M-81.4,71.45v-5.4 M-100.05,71.45
v-5.4l4.65-2.7 M-95.4,57.95l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4 M-81.4,55.25v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7
M-100.05,66.05l-4.65-2.7 M-104.7,57.95l4.65-2.7 M-86.1,41.8l-4.65-2.7v-5.4l4.65-2.7l4.7,2.7v5.4L-86.1,41.8z M-81.4,49.85
l-4.7-2.65v-5.4 M-100.05,49.85l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4 M-95.4,31l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7V31
l4.65,2.7 M-86.1,31v-5.4l4.7-2.7l4.65,2.7V31l-4.65,2.7 M-100.05,39.1v-5.4 M-90.75,39.1l-4.65,2.7 M-109.35,39.1l4.65,2.7
M-104.7,31l-4.65,2.7 M-109.35,6.75l4.65,2.7v5.4l-4.65,2.65 M-86.1,14.85v-5.4l4.7-2.7l4.65,2.7v5.4l-4.65,2.65L-86.1,14.85z
M-81.4,22.9v-5.4 M-86.1,25.6l-4.65-2.7v-5.4l4.65-2.65 M-100.05,22.9v-5.4l4.65-2.65l4.65,2.65 M-100.05,6.75v-5.4l4.65-2.7
l4.65,2.7v5.4l-4.65,2.7L-100.05,6.75z M-81.4,6.75v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7 M-90.75,6.75l4.65,2.7 M-95.4,14.85v-5.4
M-95.4,25.6l4.65-2.7 M-100.05,17.5l-4.65-2.65 M-104.7,9.45l4.65-2.7 M-109.35,22.9l4.65,2.7 M-86.1,47.2l-4.65,2.65
M-104.7,47.2l-4.65,2.65 M-11.6,95.7v-5.4l4.65-2.7l4.65,2.7 M-20.9,95.7v-5.4l4.65-2.7l4.65,2.7 M-16.25,82.2l-4.65-2.65v-5.4
l4.65-2.7l4.65,2.7v5.4L-16.25,82.2v5.4 M-2.3,79.55l-4.65,2.65l-4.65-2.65 M-6.95,82.2v5.4 M-30.2,95.7v-5.4l4.65-2.7l4.65,2.7
M-39.55,95.7v-5.4l4.7-2.7l4.65,2.7 M-39.55,79.55v-5.4l4.7-2.7l4.65,2.7v5.4l-4.65,2.65L-39.55,79.55l-4.65,2.65l-4.65-2.65
M-20.9,79.55l-4.65,2.65l-4.65-2.65 M-34.85,87.6v-5.4 M-25.55,87.6v-5.4 M-20.9,74.15l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4
M-30.2,74.15l4.65-2.7 M-25.55,66.05l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M-39.55,74.15l-4.65-2.7v-5.4l4.65-2.7l4.7,2.7v5.4
M-30.2,57.95l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4 M-39.55,63.35v-5.4l4.7-2.7 M-30.2,63.35l-4.65,2.7 M-11.6,74.15l4.65-2.7
l4.65,2.7 M-6.95,66.05l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4L-6.95,66.05v5.4 M-16.25,66.05l4.65-2.7 M-11.6,57.95l-4.65-2.7v-5.4
l4.65-2.65l4.65,2.65v5.4 M-16.25,55.25l-4.65,2.7 M-48.85,95.7v-5.4l4.65-2.7l4.65,2.7 M-58.15,95.7v-5.4l4.65-2.7l4.65,2.7
M-58.15,79.55v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65L-58.15,79.55l-4.65,2.65l-4.65-2.65 M-44.2,87.6v-5.4 M-53.5,87.6v-5.4
M-67.45,95.7v-5.4l4.65-2.7l4.65,2.7 M-76.75,90.3l4.65-2.7l4.65,2.7 M-76.75,74.15l4.65-2.7l4.65,2.7v5.4l-4.65,2.65l-4.65-2.65
M-62.8,87.6v-5.4 M-72.1,87.6v-5.4 M-67.45,74.15l4.65-2.7l4.65,2.7 M-62.8,71.45v-5.4l4.65-2.7l4.65,2.7v5.4 M-62.8,66.05
l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M-76.75,63.35l4.65,2.7v5.4 M-62.8,55.25v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7
M-67.45,63.35l-4.65,2.7 M-72.1,55.25l4.65,2.7 M-48.85,74.15l4.65-2.7 M-44.2,66.05l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7
M-53.5,49.85l4.65-2.65l4.65,2.65v5.4 M-53.5,66.05l4.65-2.7 M-53.5,55.25l4.65,2.7 M-48.85,47.2v-5.4l4.65-2.7l4.65,2.7v5.4
l-4.65,2.65 M-58.15,47.2v-5.4l4.65-2.7l4.65,2.7 M-58.15,25.6l4.65-2.7l4.65,2.7V31l-4.65,2.7l-4.65-2.7V25.6l-4.65-2.7v-5.4
M-48.85,25.6l4.65-2.7l4.65,2.7V31l-4.65,2.7l-4.65-2.7 M-44.2,39.1v-5.4 M-53.5,39.1v-5.4 M-62.8,49.85l-4.65-2.65v-5.4l4.65-2.7
l4.65,2.7 M-76.75,47.2v-5.4l4.65-2.7l4.65,2.7 M-76.75,25.6l4.65-2.7l4.65,2.7V31l-4.65,2.7l-4.65-2.7 M-58.15,31l-4.65,2.7
l-4.65-2.7 M-72.1,39.1v-5.4 M-62.8,39.1v-5.4 M-67.45,14.85v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65L-67.45,14.85l-4.65,2.65
l-4.65-2.65 M-72.1,22.9v-5.4 M-62.8,6.75v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7 M-72.1,6.75l4.65,2.7 M-44.2,22.9v-5.4l4.65-2.65
l4.7,2.65v5.4l-4.7,2.7 M-44.2,17.5l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4 M-48.85,14.85l-4.65,2.65l-4.65-2.65 M-53.5,22.9v-5.4
M-44.2,6.75v-5.4l4.65-2.7l4.7,2.7v5.4l-4.7,2.7 M-53.5,6.75l4.65,2.7 M-67.45,25.6l4.65-2.7 M-11.6,47.2v-5.4l4.65-2.7l4.65,2.7
M-11.6,41.8l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M-16.25,33.7L-20.9,31v-5.4l4.65-2.7l4.65,2.7V31 M-2.3,31l-4.65,2.7
M-30.2,47.2v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65 M-39.55,41.8l4.7-2.7l4.65,2.7 M-34.85,22.9l4.65,2.7V31l-4.65,2.7l-4.7-2.7
M-20.9,31l-4.65,2.7L-30.2,31 M-34.85,39.1v-5.4 M-25.55,39.1v-5.4 M-20.9,25.6l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4
M-25.55,17.5l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4 M-25.55,6.75v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7 M-30.2,14.85l-4.65,2.65
M-34.85,6.75l4.65,2.7 M-6.95,17.5l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4L-6.95,17.5v5.4l-4.65,2.7 M-11.6,14.85l-4.65,2.65
M-16.25,6.75l4.65,2.7 M-16.25,1.35l4.65-2.7l4.65,2.7v5.4 M-6.95,22.9l4.65,2.7 M-30.2,25.6l4.65-2.7 M-16.25,39.1l-4.65,2.7
M-67.45,47.2l-4.65,2.65 M-2.3,47.2l-4.65,2.65 M-34.85,49.85l-4.7-2.65 M-16.25,49.85l-4.65-2.65 M-81.4,39.1l4.65,2.7
M-11.6-1.35v-5.4l4.65-2.7l4.65,2.7 M-11.6-6.75l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4 M-16.25-14.85l-4.65-2.65v-5.4l4.65-2.7
l4.65,2.7v5.4 M-2.3-17.5l-4.65,2.65 M-20.9-1.35v-5.4l4.65-2.7 M-20.9-6.75l-4.65-2.7v-5.4l4.65-2.65 M-25.55-9.45l-4.65,2.7
l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65 M-30.2-6.75v5.4l-4.65,2.7 M-39.55-1.35v-5.4l4.7-2.7 M-34.85-14.85l-4.7-2.65v-5.4l4.7-2.7
l4.65,2.7v5.4 M-30.2-33.7v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7L-30.2-33.7l-4.65,2.7l-4.7-2.7v-5.4l4.7-2.7l4.65,2.7 M-20.9-22.9
l-4.65-2.7V-31 M-34.85-25.6V-31 M-39.55-39.1l-4.65-2.7v-5.4l4.65-2.65l4.7,2.65v5.4 M-25.55-41.8v-5.4l4.65-2.65l4.65,2.65v5.4
l-4.65,2.7 M-6.95-31l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4L-6.95-31v5.4l-4.65,2.7 M-16.25-25.6V-31l4.65-2.7 M-16.25-41.8
l4.65,2.7 M-16.25-47.2l4.65-2.65l4.65,2.65v5.4 M-30.2-22.9l4.65-2.7 M-16.25-31l-4.65-2.7 M-6.95-25.6l4.65,2.7 M-44.2,1.35
l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M-58.15-1.35v-5.4l4.65-2.7l4.65,2.7 M-58.15-6.75l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4
M-62.8-14.85l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4 M-39.55-17.5l-4.65,2.65l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M-44.2-9.45v-5.4
M-53.5-14.85l4.65-2.65 M-62.8,1.35l-4.65-2.7v-5.4l4.65-2.7 M-76.75-6.75l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4L-76.75-6.75
v5.4 M-76.75-17.5v-5.4l4.65-2.7l4.65,2.7 M-67.45-17.5l-4.65,2.65 M-72.1-9.45l4.65,2.7 M-67.45-33.7v-5.4l4.65-2.7l4.65,2.7v5.4
L-62.8-31L-67.45-33.7z M-62.8-25.6V-31 M-72.1-25.6V-31l4.65-2.7 M-72.1-31l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M-76.75-39.1
l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4 M-62.8-41.8v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7 M-44.2-25.6V-31l4.65-2.7 M-44.2-31
l-4.65-2.7v-5.4l4.65-2.7 M-48.85-33.7L-53.5-31l-4.65-2.7 M-48.85-22.9l-4.65-2.7V-31 M-53.5-41.8l4.65,2.7 M-58.15-22.9l4.65-2.7
M-58.15-49.85v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65 M-48.85-55.25l4.65-2.7l4.65,2.7v5.4 M-58.15-71.45l4.65-2.7l4.65,2.7v5.4
l-4.65,2.7l-4.65-2.7V-71.45z M-48.85-71.45l4.65-2.7l4.65,2.7v5.4l-4.65,2.7l-4.65-2.7 M-44.2-57.95v-5.4 M-53.5-57.95v-5.4
M-76.75-49.85v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65 M-67.45-55.25l4.65-2.7l4.65,2.7 M-76.75-55.25l-4.65-2.7v-5.4l4.65-2.7
l4.65,2.7v5.4 M-81.4-63.35l-4.7-2.7v-5.4l4.7-2.7l4.65,2.7v5.4 M-81.4-74.15v-5.4l4.65-2.65l4.65,2.65v5.4l-4.65,2.7
M-58.15-66.05l-4.65,2.7l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M-62.8-57.95v-5.4 M-72.1-74.15l4.65,2.7 M-67.45-66.05l-4.65,2.7
M-67.45-82.2v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65L-67.45-82.2l-4.65,2.65 M-76.75-82.2v-5.4l4.65-2.7l4.65,2.7 M-72.1-90.3
v-5.4 M-62.8-90.3v-5.4 M-53.5-74.15v-5.4l4.65-2.65l4.65,2.65v5.4 M-58.15-82.2l4.65,2.65 M-58.15-87.6l4.65-2.7l4.65,2.7v5.4
M-53.5-90.3v-5.4 M-44.2-95.7v5.4l-4.65,2.7 M-62.8-74.15v-5.4 M-11.6-49.85v-5.4l4.65-2.7l4.65,2.7 M-20.9-49.85v-5.4l4.65-2.7
l4.65,2.7 M-16.25-63.35l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4L-16.25-63.35v5.4 M-2.3-66.05l-4.65,2.7l-4.65-2.7 M-11.6-71.45
l4.65-2.7l4.65,2.7 M-6.95-63.35v5.4 M-25.55-47.2l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M-39.55-55.25l4.7-2.7l4.65,2.7
M-39.55-71.45l4.7-2.7l4.65,2.7v5.4l-4.65,2.7l-4.7-2.7 M-20.9-71.45l-4.65-2.7v-5.4l4.65-2.65l4.65,2.65v5.4 M-20.9-66.05
l-4.65,2.7l-4.65-2.7 M-25.55-74.15l-4.65,2.7 M-34.85-63.35v5.4 M-25.55-57.95v-5.4 M-34.85-74.15v-5.4l4.65-2.65l4.65,2.65
M-44.2-79.55l4.65-2.65l4.7,2.65 M-39.55-82.2v-5.4l4.7-2.7l4.65,2.7v5.4 M-34.85-90.3v-5.4 M-16.25-95.7v5.4l-4.65,2.7l-4.65-2.7
v-5.4 M-25.55-90.3l-4.65,2.7 M-20.9-82.2v-5.4 M-6.95-79.55l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7v5.4L-6.95-79.55v5.4 M-16.25-79.55
l4.65-2.65 M-11.6-87.6l-4.65-2.7 M-6.95-95.7v5.4 M-44.2-90.3l4.65,2.7 M-62.8-47.2l-4.65-2.65 M-44.2-47.2l-4.65-2.65
M-30.2-49.85l-4.65,2.65 M-2.3-49.85l-4.65,2.65 M-95.4-1.35v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.7 M-86.1-6.75l4.7-2.7
M-100.05,1.35l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7 M-95.4-17.5l-4.65,2.65l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7V-17.5z M-95.4-22.9
l4.65-2.7l4.65,2.7v5.4l-4.65,2.65l-4.65-2.65 M-81.4-14.85l-4.7-2.65 M-100.05-9.45v-5.4 M-90.75-14.85v5.4 M-109.35-9.45
l4.65,2.7 M-104.7-17.5l-4.65,2.65 M-109.35-41.8l4.65,2.7v5.4l-4.65,2.7 M-90.75-25.6V-31l4.65-2.7l4.7,2.7v5.4l-4.7,2.7
M-100.05-25.6V-31l4.65-2.7l4.65,2.7 M-100.05-47.2l4.65-2.65l4.65,2.65v5.4l-4.65,2.7l-4.65-2.7V-47.2l-4.65-2.65 M-90.75-41.8
l4.65,2.7v5.4 M-86.1-39.1l4.7-2.7 M-95.4-33.7v-5.4 M-109.35-25.6l4.65,2.7 M-100.05-31l-4.65-2.7 M-104.7-39.1l4.65-2.7
M-95.4-49.85v-5.4l4.65-2.7l4.65,2.7v5.4l-4.65,2.65 M-86.1-55.25l4.7-2.7 M-95.4-55.25l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4
M-100.05-63.35l-4.65-2.7v-5.4l4.65-2.7l4.65,2.7v5.4 M-95.4-71.45l4.65-2.7l4.65,2.7 M-86.1-66.05l-4.65,2.7 M-109.35-57.95
l4.65,2.7v5.4l-4.65,2.65 M-109.35-74.15l4.65,2.7 M-104.7-66.05l-4.65,2.7 M-109.35-90.3l4.65,2.7v5.4l-4.65,2.65 M-81.4-79.55
l-4.7-2.65v-5.4l4.7-2.7l4.65,2.7 M-86.1-82.2l-4.65,2.65l-4.65-2.65v-5.4l4.65-2.7l4.65,2.7 M-100.05-74.15v-5.4l4.65-2.65
M-95.4-87.6l-4.65-2.7v-5.4 M-81.4-95.7v5.4 M-90.75-95.7v5.4 M-90.75-79.55v5.4 M-104.7-55.25l4.65-2.7 M-100.05-79.55
l-4.65-2.65 M-104.7-87.6l4.65-2.7 M-81.4-47.2l-4.7-2.65 M-76.75-33.7L-81.4-31 M-81.4-25.6l4.65,2.7 M-67.45-1.35l-4.65,2.7
M-104.7-1.35l-4.65,2.7 M-81.4,1.35l-4.7-2.7 M-25.55,1.35l-4.65-2.7 M-53.5,1.35l4.65-2.7 M-2.3-1.35l-4.65,2.7 M-2.3,57.95
l4.65-2.7 M2.35,66.05l-4.65-2.7 M-2.3-39.1l4.65-2.7 M2.35-31l-4.65-2.7 M2.35-79.55L-2.3-82.2 M-2.3-87.6l4.65-2.7 M-2.3,9.45
l4.65-2.7 M2.35,17.5l-4.65-2.65"/>
</symbol>
<g id="Layer_1">
</g>
<g id="Layer_6">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#EFEEEE" d="M217.5,108.95c0,29.833-10.533,55.399-31.6,76.7
c-0.7,0.833-1.484,1.6-2.351,2.3c-3.466,3.399-7.134,6.483-11,9.25c-18.267,13.467-39.366,20.2-63.3,20.2
c-23.967,0-45.033-6.733-63.2-20.2c-4.8-3.4-9.3-7.25-13.5-11.55c-16.367-16.267-26.417-35.167-30.15-56.7
c-0.733-4.2-1.217-8.467-1.45-12.8c-0.1-2.4-0.15-4.801-0.15-7.2c0-2.534,0.05-4.95,0.15-7.25c0-0.233,0.066-0.467,0.2-0.7
c1.567-26.6,12.033-49.583,31.4-68.95C53.85,11.017,79.417,0.5,109.25,0.5c29.934,0,55.483,10.517,76.65,31.55
C206.967,53.483,217.5,79.117,217.5,108.95z"/>
</g>
<g id="Layer_5">
<path fill-rule="evenodd" clip-rule="evenodd" fill="#010101" d="M195.45,43l-22.4,22.4c-8.833,13-13.25,27.867-13.25,44.6
c0,17.934,5.067,33.833,15.2,47.7l19,18.95c-2.5,3.066-5.2,6.066-8.1,9c-0.7,0.833-1.484,1.6-2.351,2.3
c-2.533,2.5-5.167,4.816-7.899,6.95L158.1,177.35c-13.934-10.733-30.133-16.1-48.6-16.1c-17.933,0-33.833,5.1-47.7,15.3
L43.25,195.15c-3.767-2.867-7.333-6.034-10.7-9.5c-2.8-2.801-5.417-5.667-7.85-8.601l19.15-19.2
c10.066-13.966,15.1-29.916,15.1-47.85c0-17.5-4.867-33.017-14.6-46.55l-21.05-21c2.833-3.6,5.917-7.067,9.25-10.4
c2.934-2.867,5.934-5.55,9-8.05L61.9,44.35C75.7,54.583,91.567,59.7,109.5,59.7c18.467,0,34.666-5.367,48.6-16.1L177.4,24.35
c2.899,2.367,5.732,4.933,8.5,7.7C189.367,35.583,192.55,39.233,195.45,43z"/>
</g>
<g id="Layer_4">
<defs>
<path id="SVGID_1_" d="M159.8,110c0-16.733,4.417-31.6,13.25-44.6l22.4-22.4c-2.9-3.767-6.083-7.417-9.55-10.95
c-2.768-2.767-5.601-5.333-8.5-7.7L158.1,43.6c-13.934,10.733-30.133,16.1-48.6,16.1c-17.933,0-33.8-5.117-47.6-15.35L41.55,24
c-3.066,2.5-6.066,5.183-9,8.05c-3.333,3.333-6.417,6.8-9.25,10.4l21.05,21c9.733,13.533,14.6,29.05,14.6,46.55
c0,17.934-5.034,33.884-15.1,47.85l-19.15,19.2c2.433,2.934,5.05,5.8,7.85,8.601c3.367,3.466,6.934,6.633,10.7,9.5L61.8,176.55
c13.867-10.2,29.767-15.3,47.7-15.3c18.467,0,34.666,5.366,48.6,16.1L175.65,194.9c2.732-2.134,5.366-4.45,7.899-6.95
c0.866-0.7,1.65-1.467,2.351-2.3c2.899-2.934,5.6-5.934,8.1-9l-19-18.95C164.867,143.833,159.8,127.934,159.8,110z"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_2_)">
<use xlink:href="#hex_grid" width="228.55" height="197.233" x="-114.25" y="-98.617" transform="matrix(1.1415 0 0 -1.1415 105.5 107.75)" overflow="visible"/>
</g>
</g>
<g id="Layer_2">
<g>
<path fill-rule="evenodd" clip-rule="evenodd" fill="#35C6F4" d="M79.1,110.95c-0.033-0.667-0.05-1.333-0.05-2
c0-0.7,0.017-1.366,0.05-2c0-0.067,0.017-0.134,0.05-0.2c0.434-7.367,3.333-13.733,8.7-19.1c5.9-5.833,12.983-8.75,21.25-8.75
c8.301,0,15.384,2.917,21.25,8.75c5.834,5.934,8.75,13.033,8.75,21.3c0,8.267-2.916,15.35-8.75,21.25
c-0.199,0.233-0.416,0.45-0.649,0.649c-0.967,0.934-1.983,1.784-3.05,2.551c-5.066,3.733-10.917,5.6-17.551,5.6
c-6.633,0-12.466-1.866-17.5-5.6c-1.333-0.934-2.583-2-3.75-3.2c-4.533-4.5-7.317-9.733-8.35-15.7
C79.3,113.334,79.167,112.15,79.1,110.95z M126.1,127.25l3.601,3.6L126.1,127.25z"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#35C6F4" stroke-width="2" stroke-miterlimit="1" d="
M158.6,60.25l-15,14.65 M31.7,33.1l40.75,40.65 M126.1,127.25l3.601,3.6 M157.05,158l27.65,28.6 M153.05,153.95l-10.75-11.2
M186.6,33l-28,27.25 M33.15,186.25l27.35-27.4"/>
<path fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#35C6F4" stroke-width="7" stroke-miterlimit="1" d="
M158.6,60.25l-16.949,17.2 M59.4,61.35L76.6,78.5 M60.5,158.85l16.75-17.399 M153.05,153.95l4,4.05 M139.45,140.4l13.6,13.55"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

115
README.md
View File

@@ -1,115 +1,52 @@
<p align="center">
<img src="/Logo/text256.png" alt="Radarr">
</p>
# Sonarr
Radarr is an __independent__ fork of [Sonarr](https://github.com/Sonarr/Sonarr) reworked for automatically downloading movies via Usenet and BitTorrent.
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.
The project was inspired by other Usenet/BitTorrent movie downloaders such as CouchPotato.
## Major Features Include:
## Getting Started
[![Installation](https://img.shields.io/badge/wiki-installation-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/wiki/Installation)
[![Docker](https://img.shields.io/badge/wiki-docker-1488C6.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/wiki/Docker)
[![Setup Guide](https://img.shields.io/badge/wiki-setup_guide-orange.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/wiki/Setup-Guide)
[![FAQ](https://img.shields.io/badge/wiki-FAQ-BF55EC.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/wiki/FAQ)
* [Install Radarr for your desired OS](https://github.com/Radarr/Radarr/wiki/Installation) *or* use [Docker](https://github.com/Radarr/Radarr/wiki/Docker)
* *For Linux users*, run `radarr` and *optionally* have [Radarr start automatically](https://github.com/Radarr/Radarr/wiki/Autostart-on-Linux)
* Connect to the UI through <http://localhost:7878> or <http://your-ip:7878> in your web browser
* See the [Setup Guide](https://github.com/Radarr/Radarr/wiki/Setup-Guide) for further configuration
## Downloads
[![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases)
[![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/build/artifacts)
[![Docker release](https://img.shields.io/badge/docker-release-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr)
[![Docker nightly](https://img.shields.io/badge/docker-nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/hotio/radarr)
[![Docker armhf](https://img.shields.io/badge/docker-armhf-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr)
[![Docker aarch64](https://img.shields.io/badge/docker-aarch64-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
## Support
[![Discord](https://img.shields.io/badge/discord-chat-7289DA.svg?maxAge=60&style=flat-square)](https://discord.gg/AD3UP37)
[![Reddit](https://img.shields.io/badge/reddit-discussion-FF4500.svg?maxAge=60&style=flat-square)](https://www.reddit.com/r/radarr)
[![Feathub](https://img.shields.io/badge/feathub-requests-lightgrey.svg?maxAge=60&style=flat-square)](http://feathub.com/Radarr/Radarr)
[![GitHub](https://img.shields.io/badge/github-issues-red.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/issues)
[![GitHub Wiki](https://img.shields.io/badge/github-wiki-181717.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/wiki)
## Status
[![GitHub issues](https://img.shields.io/github/issues/radarr/radarr.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/radarr/radarr.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/pulls)
[![GNU GPL v3](https://img.shields.io/badge/license-GNU%20GPL%20v3-blue.svg?maxAge=60&style=flat-square)](http://www.gnu.org/licenses/gpl.html)
[![Copyright 2010-2017](https://img.shields.io/badge/copyright-2017-blue.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr)
[![Github Releases](https://img.shields.io/github/downloads/Radarr/Radarr/total.svg?maxAge=60&style=flat-square)](https://github.com/Radar/Radarr/releases/latest)
[![Docker Pulls](https://img.shields.io/docker/pulls/linuxserver/radarr.svg?maxAge=60&style=flat-square)](https://hub.docker.com/r/linuxserver/radarr/)
| Service | Master | Develop |
|----------|:---------------------------:|:----------------------------:|
| AppVeyor | [![AppVeyor](https://img.shields.io/appveyor/ci/galli-leo/Radarr/master.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/Radarr) | [![AppVeyor](https://img.shields.io/appveyor/ci/galli-leo/Radarr-usby1/develop.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/Radarr-usby1) |
| Travis | [![Travis](https://img.shields.io/travis/Radarr/Radarr/master.svg?maxAge=60&style=flat-square)](https://travis-ci.org/Radarr/Radarr) | [![Travis](https://img.shields.io/travis/Radarr/Radarr/develop.svg?maxAge=60&style=flat-square)](https://travis-ci.org/Radarr/Radarr) |
**This project works independently of Sonarr and will not interfere with it.**
Radarr is currently undergoing rapid development and pull requests are actively added into the repository.
## Features
### Current Features
* Adding new movies with lots of information, such as trailers, ratings, etc.
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
* Can watch for better quality of the movies you have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
* 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
* Automatically searching for releases as well as RSS Sync
* Automatically importing downloaded movies
* Recognizing Special Editions, Director's Cut, etc.
* Identifying releases with hardcoded subs
* All indexers supported by Sonarr also supported
* New PassThePopcorn Indexer
* QBittorrent, Deluge, rTorrent, Transmission and uTorrent download client (Other clients are coming)
* New TorrentPotato Indexer (Works well with [Jackett](https://github.com/Jackett/Jackett))
* Full integration with Kodi, Plex (notification, library update, metadata)
* Full support for specials and multi-episode releases
* And a beautiful UI
### Planned Features
* Scanning PreDB to know when a new release is available
* Fixing the other Indexers and download clients
* Importing movies from various online sources, such as IMDb Watchlists (A complete list can be found [here](https://github.com/Radarr/Radarr/issues/114))
* Full integration with Kodi, Plex (notification, library update, metadata)
#### [Feature Requests](http://feathub.com/Radarr/Radarr)
## Configuring the Development Environment
## Configuring Development Environment:
### Requirements
* [Visual Studio Community](https://www.visualstudio.com/vs/community/) or [MonoDevelop](http://www.monodevelop.com)
* Visual Studio 2015 (https://www.visualstudio.com/vs/)
* [Git](https://git-scm.com/downloads)
* [Node.js](https://nodejs.org/en/download/)
* [NodeJS](https://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/desktop/guides/contributing/working-with-your-remote-repository-on-github-or-github-enterprise))
* 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.
> **Notice**
> Gulp must be running at all times while you are working with Radarr client source files.
*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 or run the build.sh script, if Mono is installed
* Open `NzbDrone.sln` in Visual Studio
* Make sure `NzbDrone.Console` is set as the startup project
## Sponsors
### License
Thanks to [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)
* [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,44 +0,0 @@
version: '0.2.0.{build}'
assembly_info:
patch: true
file: 'src\NzbDrone.Common\Properties\SharedAssemblyInfo.cs'
assembly_version: '{version}'
assembly_file_version: '{version}'
assembly_informational_version: '{version}-rc1'
environment:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
install:
- git submodule update --init --recursive
build_script:
- ps: ./build-appveyor.ps1
# test: off
test:
assemblies:
- '_tests\*Test.dll'
categories:
except:
- IntegrationTest
- AutomationTest
artifacts:
- path: '_artifacts\*.zip'
- path: '_artifacts\*.tar.gz'
cache:
- '%USERPROFILE%\.nuget\packages'
- node_modules
pull_requests:
do_not_increment_build_number: true
only_commits:
files:
- src/
- osx/
- gulp/
- logo/

View File

@@ -1,303 +0,0 @@
#addin "Cake.Npm"
#addin "SharpZipLib"
#addin "Cake.Compression"
// Build variables
var outputFolder = "./_output";
var outputFolderMono = outputFolder + "_mono";
var outputFolderOsx = outputFolder + "_osx";
var outputFolderOsxApp = outputFolderOsx + "_app";
var testPackageFolder = "./_tests";
var testSearchPattern = "*.Test/bin/x86/Release";
var sourceFolder = "./src";
var solutionFile = sourceFolder + "/NzbDrone.sln";
var updateFolder = outputFolder + "/NzbDrone.Update";
var updateFolderMono = outputFolderMono + "/NzbDrone.Update";
// Artifact variables
var artifactsFolder = "./_artifacts";
var artifactsFolderWindows = artifactsFolder + "/windows";
var artifactsFolderLinux = artifactsFolder + "/linux";
var artifactsFolderOsx = artifactsFolder + "/osx";
var artifactsFolderOsxApp = artifactsFolder + "/osx-app";
// Utility methods
public void RemoveEmptyFolders(string startLocation) {
foreach (var directory in System.IO.Directory.GetDirectories(startLocation))
{
RemoveEmptyFolders(directory);
if (System.IO.Directory.GetFiles(directory).Length == 0 &&
System.IO.Directory.GetDirectories(directory).Length == 0)
{
DeleteDirectory(directory, false);
}
}
}
public void CleanFolder(string path, bool keepConfigFiles) {
DeleteFiles(path + "/**/*.transform");
if (!keepConfigFiles) {
DeleteFiles(path + "/**/*.dll.config");
}
DeleteFiles(path + "/**/FluentValidation.resources.dll");
DeleteFiles(path + "/**/App.config");
DeleteFiles(path + "/**/*.less");
DeleteFiles(path + "/**/*.vshost.exe");
DeleteFiles(path + "/**/*.dylib");
RemoveEmptyFolders(path);
}
public void CreateMdbs(string path) {
foreach (var file in System.IO.Directory.EnumerateFiles(path, "*.pdb", System.IO.SearchOption.AllDirectories)) {
var actualFile = file.Substring(0, file.Length - 4);
if (FileExists(actualFile + ".exe")) {
StartProcess("./tools/pdb2mdb/pdb2mdb.exe", new ProcessSettings()
.WithArguments(args => args.Append(actualFile + ".exe")));
}
if (FileExists(actualFile + ".dll")) {
StartProcess("./tools/pdb2mdb/pdb2mdb.exe", new ProcessSettings()
.WithArguments(args => args.Append(actualFile + ".dll")));
}
}
}
// Build Tasks
Task("Compile").Does(() => {
// Build
if (DirectoryExists(outputFolder)) {
DeleteDirectory(outputFolder, true);
}
MSBuild(solutionFile, config =>
config.UseToolVersion(MSBuildToolVersion.VS2015)
.WithTarget("Clean")
.SetVerbosity(Verbosity.Minimal));
NuGetRestore(solutionFile);
MSBuild(solutionFile, config =>
config.UseToolVersion(MSBuildToolVersion.VS2015)
.SetPlatformTarget(PlatformTarget.x86)
.SetConfiguration("Release")
.WithProperty("AllowedReferenceRelatedFileExtensions", new string[] { ".pdb" })
.WithTarget("Build")
.SetVerbosity(Verbosity.Minimal));
CleanFolder(outputFolder, false);
// Add JsonNet
DeleteFiles(outputFolder + "/Newtonsoft.Json.*");
CopyFiles(sourceFolder + "/packages/Newtonsoft.Json.*/lib/net35/*.dll", outputFolder);
CopyFiles(sourceFolder + "/packages/Newtonsoft.Json.*/lib/net35/*.dll", updateFolder);
// Remove Mono stuff
DeleteFile(outputFolder + "/Mono.Posix.dll");
});
Task("Gulp").Does(() => {
Npm
.WithLogLevel(NpmLogLevel.Silent)
.FromPath(".")
.Install()
.RunScript("build");
});
Task("PackageMono").Does(() => {
// Start mono package
if (DirectoryExists(outputFolderMono)) {
DeleteDirectory(outputFolderMono, true);
}
CopyDirectory(outputFolder, outputFolderMono);
// Create MDBs
CreateMdbs(outputFolderMono);
// Remove PDBs
DeleteFiles(outputFolderMono + "/**/*.pdb");
// Remove service helpers
DeleteFiles(outputFolderMono + "/ServiceUninstall.*");
DeleteFiles(outputFolderMono + "/ServiceInstall.*");
// Remove native windows binaries
DeleteFiles(outputFolderMono + "/sqlite3.*");
DeleteFiles(outputFolderMono + "/MediaInfo.*");
// Adding NzbDrone.Core.dll.config (for dllmap)
CopyFile(sourceFolder + "/NzbDrone.Core/NzbDrone.Core.dll.config", outputFolderMono + "/NzbDrone.Core.dll.config");
// Adding CurlSharp.dll.config (for dllmap)
CopyFile(sourceFolder + "/NzbDrone.Common/CurlSharp.dll.config", outputFolderMono + "/CurlSharp.dll.config");
// Renaming Radarr.Console.exe to Radarr.exe
DeleteFiles(outputFolderMono + "/Radarr.exe*");
MoveFile(outputFolderMono + "/Radarr.Console.exe", outputFolderMono + "/Radarr.exe");
MoveFile(outputFolderMono + "/Radarr.Console.exe.config", outputFolderMono + "/Radarr.exe.config");
MoveFile(outputFolderMono + "/Radarr.Console.exe.mdb", outputFolderMono + "/Radarr.exe.mdb");
// Remove NzbDrone.Windows.*
DeleteFiles(outputFolderMono + "/NzbDrone.Windows.*");
// Adding NzbDrone.Mono to updatePackage
CopyFiles(outputFolderMono + "/NzbDrone.Mono.*", updateFolderMono);
});
Task("PackageOsx").Does(() => {
// Start osx package
if (DirectoryExists(outputFolderOsx)) {
DeleteDirectory(outputFolderOsx, true);
}
CopyDirectory(outputFolderMono, outputFolderOsx);
// Adding sqlite dylibs
CopyFiles(sourceFolder + "/Libraries/Sqlite/*.dylib", outputFolderOsx);
// Adding MediaInfo dylib
CopyFiles(sourceFolder + "/Libraries/MediaInfo/*.dylib", outputFolderOsx);
// Adding Startup script
CopyFile("./osx/Sonarr", outputFolderOsx + "/Sonarr");
});
Task("PackageOsxApp").Does(() => {
// Start osx app package
if (DirectoryExists(outputFolderOsxApp)) {
DeleteDirectory(outputFolderOsxApp, true);
}
CreateDirectory(outputFolderOsxApp);
// Copy osx package files
CopyDirectory("./osx/Radarr.app", outputFolderOsxApp + "/Radarr.app");
CopyDirectory(outputFolderOsx, outputFolderOsxApp + "/Radarr.app/Contents/MacOS");
});
Task("PackageTests").Does(() => {
// Start tests package
if (DirectoryExists(testPackageFolder)) {
DeleteDirectory(testPackageFolder, true);
}
CreateDirectory(testPackageFolder);
// Copy tests
CopyFiles(sourceFolder + "/" + testSearchPattern + "/*", testPackageFolder);
foreach (var directory in System.IO.Directory.GetDirectories(sourceFolder, "*.Test")) {
var releaseDirectory = directory + "/bin/x86/Release";
if (DirectoryExists(releaseDirectory)) {
foreach (var releaseSubDirectory in System.IO.Directory.GetDirectories(releaseDirectory)) {
Information(System.IO.Path.GetDirectoryName(releaseSubDirectory));
CopyDirectory(releaseSubDirectory, testPackageFolder + "/" + System.IO.Path.GetFileName(releaseSubDirectory));
}
}
}
// Install NUnit.ConsoleRunner
NuGetInstall("NUnit.ConsoleRunner", new NuGetInstallSettings {
Version = "3.2.0",
OutputDirectory = testPackageFolder
});
// Copy dlls
CopyFiles(outputFolder + "/*.dll", testPackageFolder);
// Copy scripts
CopyFiles("./*.sh", testPackageFolder);
// Create MDBs for tests
CreateMdbs(testPackageFolder);
// Remove config
DeleteFiles(testPackageFolder + "/*.log.config");
// Clean
CleanFolder(testPackageFolder, true);
// Adding NzbDrone.Core.dll.config (for dllmap)
CopyFile(sourceFolder + "/NzbDrone.Core/NzbDrone.Core.dll.config", testPackageFolder + "/NzbDrone.Core.dll.config");
// Adding CurlSharp.dll.config (for dllmap)
CopyFile(sourceFolder + "/NzbDrone.Common/CurlSharp.dll.config", testPackageFolder + "/CurlSharp.dll.config");
// Adding CurlSharp libraries
CopyFiles(sourceFolder + "/ExternalModules/CurlSharp/libs/i386/*", testPackageFolder);
});
Task("CleanupWindowsPackage").Does(() => {
// Remove mono
DeleteFiles(outputFolder + "/NzbDrone.Mono.*");
// Adding NzbDrone.Windows to updatePackage
CopyFiles(outputFolder + "/NzbDrone.Windows.*", updateFolder);
});
Task("Build")
.IsDependentOn("Compile")
.IsDependentOn("Gulp")
.IsDependentOn("PackageMono")
.IsDependentOn("PackageOsx")
.IsDependentOn("PackageOsxApp")
.IsDependentOn("PackageTests")
.IsDependentOn("CleanupWindowsPackage");
// Build Artifacts
Task("CleanArtifacts").Does(() => {
if (DirectoryExists(artifactsFolder)) {
DeleteDirectory(artifactsFolder, true);
}
CreateDirectory(artifactsFolder);
});
Task("ArtifactsWindows").Does(() => {
CopyDirectory(outputFolder, artifactsFolderWindows + "/Radarr");
});
Task("ArtifactsLinux").Does(() => {
CopyDirectory(outputFolderMono, artifactsFolderLinux + "/Radarr");
});
Task("ArtifactsOsx").Does(() => {
CopyDirectory(outputFolderOsx, artifactsFolderOsx + "/Radarr");
});
Task("ArtifactsOsxApp").Does(() => {
CopyDirectory(outputFolderOsxApp, artifactsFolderOsxApp);
});
Task("CompressArtifacts").Does(() => {
var prefix = "";
if (AppVeyor.IsRunningOnAppVeyor) {
prefix += AppVeyor.Environment.Repository.Branch.Replace("/", "-") + ".";
prefix += AppVeyor.Environment.Build.Version + ".";
}
Zip(artifactsFolderWindows, artifactsFolder + "/Radarr." + prefix + "windows.zip");
GZipCompress(artifactsFolderLinux, artifactsFolder + "/Radarr." + prefix + "linux.tar.gz");
GZipCompress(artifactsFolderOsx, artifactsFolder + "/Radarr." + prefix + "osx.tar.gz");
Zip(artifactsFolderOsxApp, artifactsFolder + "/Radarr." + prefix + "osx-app.zip");
});
Task("Artifacts")
.IsDependentOn("CleanArtifacts")
.IsDependentOn("ArtifactsWindows")
.IsDependentOn("ArtifactsLinux")
.IsDependentOn("ArtifactsOsx")
.IsDependentOn("ArtifactsOsxApp")
.IsDependentOn("CompressArtifacts");
// Run
RunTarget("Build");
RunTarget("Artifacts");

View File

@@ -1,184 +0,0 @@
##########################################################################
# This is the Cake bootstrapper script for PowerShell.
# This file was downloaded from https://github.com/cake-build/resources
# Feel free to change this file to fit your needs.
##########################################################################
<#
.SYNOPSIS
This is a Powershell script to bootstrap a Cake build.
.DESCRIPTION
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
and execute your Cake build script with the parameters you provide.
.PARAMETER Script
The build script to execute.
.PARAMETER Target
The build script target to run.
.PARAMETER Configuration
The build configuration to use.
.PARAMETER Verbosity
Specifies the amount of information to be displayed.
.PARAMETER Experimental
Tells Cake to use the latest Roslyn release.
.PARAMETER WhatIf
Performs a dry run of the build script.
No tasks will be executed.
.PARAMETER Mono
Tells Cake to use the Mono scripting engine.
.PARAMETER SkipToolPackageRestore
Skips restoring of packages.
.PARAMETER ScriptArgs
Remaining arguments are added here.
.LINK
http://cakebuild.net
#>
[CmdletBinding()]
Param(
[string]$Script = "build-appveyor.cake",
[string]$Target = "Default",
[ValidateSet("Release", "Debug")]
[string]$Configuration = "Release",
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity = "Verbose",
[switch]$Experimental,
[Alias("DryRun","Noop")]
[switch]$WhatIf,
[switch]$Mono,
[switch]$SkipToolPackageRestore,
[Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
[string[]]$ScriptArgs
)
[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
function MD5HashFile([string] $filePath)
{
if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
{
return $null
}
[System.IO.Stream] $file = $null;
[System.Security.Cryptography.MD5] $md5 = $null;
try
{
$md5 = [System.Security.Cryptography.MD5]::Create()
$file = [System.IO.File]::OpenRead($filePath)
return [System.BitConverter]::ToString($md5.ComputeHash($file))
}
finally
{
if ($file -ne $null)
{
$file.Dispose()
}
}
}
Write-Host "Preparing to run build script..."
if(!$PSScriptRoot){
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
}
$TOOLS_DIR = Join-Path $PSScriptRoot "tools-cake"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
# Should we use mono?
$UseMono = "";
if($Mono.IsPresent) {
Write-Verbose -Message "Using the Mono based scripting engine."
$UseMono = "-mono"
}
# Should we use the new Roslyn?
$UseExperimental = "";
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
Write-Verbose -Message "Using experimental version of Roslyn."
$UseExperimental = "-experimental"
}
# Is this a dry run?
$UseDryRun = "";
if($WhatIf.IsPresent) {
$UseDryRun = "-dryrun"
}
# Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
Write-Verbose -Message "Creating tools directory..."
New-Item -Path $TOOLS_DIR -Type directory | out-null
}
# Make sure that packages.config exist.
if (!(Test-Path $PACKAGES_CONFIG)) {
Write-Verbose -Message "Downloading packages.config..."
try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
Throw "Could not download packages.config."
}
}
# Try find NuGet.exe in path if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Trying to find nuget.exe in PATH..."
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) }
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
$NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
}
}
# Try download NuGet.exe if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..."
try {
(New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
} catch {
Throw "Could not download NuGet.exe."
}
}
# Save nuget.exe path to environment to be available to child processed
$ENV:NUGET_EXE = $NUGET_EXE
# Restore tools from NuGet?
if(-Not $SkipToolPackageRestore.IsPresent) {
Push-Location
Set-Location $TOOLS_DIR
# Check for changes in packages.config and remove installed tools if true.
[string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
Write-Verbose -Message "Missing or changed package.config hash..."
Remove-Item * -Recurse -Exclude packages.config,nuget.exe
}
Write-Verbose -Message "Restoring tools from NuGet..."
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
if ($LASTEXITCODE -ne 0) {
Throw "An error occured while restoring NuGet tools."
}
else
{
$md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
}
Write-Verbose -Message ($NuGetOutput | out-string)
Pop-Location
}
# Make sure that Cake has been installed.
if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe at $CAKE_EXE"
}
# Start Cake
Write-Host "Running build script..."
Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
exit $LASTEXITCODE

View File

@@ -154,8 +154,8 @@ PackageMono()
cp $sourceFolder/NzbDrone.Common/CurlSharp.dll.config $outputFolderMono
echo "Renaming NzbDrone.Console.exe to NzbDrone.exe"
rm $outputFolderMono/Radarr.exe*
for file in $outputFolderMono/Radarr.Console.exe*; do
rm $outputFolderMono/NzbDrone.exe*
for file in $outputFolderMono/NzbDrone.Console.exe*; do
mv "$file" "${file//.Console/}"
done
@@ -192,8 +192,8 @@ PackageOsxApp()
rm -rf $outputFolderOsxApp
mkdir $outputFolderOsxApp
cp -r ./osx/Radarr.app $outputFolderOsxApp
cp -r $outputFolderOsx $outputFolderOsxApp/Radarr.app/Contents/MacOS
cp -r ./osx/Sonarr.app $outputFolderOsxApp
cp -r $outputFolderOsx $outputFolderOsxApp/Sonarr.app/Contents/MacOS
echo "##teamcity[progressFinish 'Creating OS X App Package']"
}

View File

@@ -19,16 +19,13 @@ gulp.task('less', function() {
paths.src.root + 'Series/series.less',
paths.src.root + 'Activity/activity.less',
paths.src.root + 'AddSeries/addSeries.less',
paths.src.root + 'AddMovies/addMovies.less',
paths.src.root + 'Calendar/calendar.less',
paths.src.root + 'Cells/cells.less',
paths.src.root + 'ManualImport/manualimport.less',
paths.src.root + 'Settings/settings.less',
paths.src.root + 'System/Logs/logs.less',
paths.src.root + 'System/Update/update.less',
paths.src.root + 'System/Info/info.less',
paths.src.root + 'Movies/movies.less',
paths.src.root + 'System/Info/info.less'
];
return gulp.src(src)

View File

@@ -4,9 +4,9 @@
DIR=$(cd "$(dirname "$0")"; pwd)
#change these values to match your app
EXE_PATH="$DIR/Radarr.exe"
EXE_PATH="$DIR/NzbDrone.exe"
APPNAME="Sonarr"
#set up environment
if [[ -x '/opt/local/bin/mono' ]]; then
export PATH="/opt/local/bin:$PATH"
@@ -29,11 +29,11 @@ export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$HOME/lib:/usr/lo
#mono version check
REQUIRED_MAJOR=3
REQUIRED_MINOR=10
VERSION_TITLE="Cannot launch $APPNAME"
VERSION_MSG="$APPNAME requires Mono Runtime Environment(MRE) $REQUIRED_MAJOR.$REQUIRED_MINOR or later."
DOWNLOAD_URL="http://www.mono-project.com/download/#download-mac"
MONO_VERSION="$(mono --version | grep 'Mono JIT compiler version ' | cut -f5 -d\ )"
# if [[ -o DEBUG ]]; then osascript -e "display dialog \"MONO_VERSION: $MONO_VERSION\""; fi
@@ -42,7 +42,7 @@ MONO_VERSION_MAJOR="$(echo $MONO_VERSION | cut -f1 -d.)"
MONO_VERSION_MINOR="$(echo $MONO_VERSION | cut -f2 -d.)"
if [ -z "$MONO_VERSION" ] \
|| [ $MONO_VERSION_MAJOR -lt $REQUIRED_MAJOR ] \
|| [ $MONO_VERSION_MAJOR -eq $REQUIRED_MAJOR -a $MONO_VERSION_MINOR -lt $REQUIRED_MINOR ]
|| [ $MONO_VERSION_MAJOR -eq $REQUIRED_MAJOR -a $MONO_VERSION_MINOR -lt $REQUIRED_MINOR ]
then
osascript \
-e "set question to display dialog \"$VERSION_MSG\" with title \"$VERSION_TITLE\" buttons {\"Cancel\", \"Download...\"} default button 2" \
@@ -51,8 +51,8 @@ then
echo "$VERSION_MSG"
exit 1
fi
MONO_EXEC="exec mono --debug"
#run app using mono
$MONO_EXEC "$EXE_PATH"
$MONO_EXEC "$EXE_PATH"

View File

@@ -13,7 +13,7 @@
<key>CFBundleExecutable</key>
<string>Sonarr</string>
<key>CFBundleIconFile</key>
<string>radarr.icns</string>
<string>sonarr.icns</string>
<key>CFBundleIdentifier</key>
<string>com.osx.sonarr.tv</string>
<key>CFBundleInfoDictionaryVersion</key>

View File

@@ -40,7 +40,6 @@
"run-sequence": "1.1.1",
"streamqueue": "1.1.0",
"tar.gz": "0.1.1",
"url-search-params": "^0.6.1",
"webpack": "1.12.0",
"webpack-stream": "2.1.0"
}

View File

@@ -1,68 +0,0 @@
if [ $# -eq 0 ]; then
if [ "$TRAVIS_PULL_REQUEST" != false ]; then
echo "Need to supply version argument" && exit;
fi
fi
# Use mono or .net depending on OS
case "$(uname -s)" in
CYGWIN*|MINGW32*|MINGW64*|MSYS*)
# on windows, use dotnet
runtime="dotnet"
;;
*)
# otherwise use mono
runtime="mono"
;;
esac
if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
VERSION="`date +%H:%M:%S`"
YEAR="`date +%Y`"
MONTH="`date +%m`"
DAY="`date +%d`"
else
VERSION=$1
fi
outputFolder='./_output'
outputFolderMono='./_output_mono'
outputFolderOsx='./_output_osx'
outputFolderOsxApp='./_output_osx_app'
tr -d "\r" < $outputFolderOsxApp/Radarr.app/Contents/MacOS/Sonarr > $outputFolderOsxApp/Radarr.app/Contents/MacOS/Sonarr2
rm $outputFolderOsxApp/Radarr.app/Contents/MacOS/Sonarr
chmod +x $outputFolderOsxApp/Radarr.app/Contents/MacOS/Sonarr2
mv $outputFolderOsxApp/Radarr.app/Contents/MacOS/Sonarr2 $outputFolderOsxApp/Radarr.app/Contents/MacOS/Sonarr >& error.log
cp -r $outputFolder/ Radarr_Windows_$VERSION
cp -r $outputFolderMono/ Radarr_Mono_$VERSION
cp -r $outputFolderOsxApp/ Radarr_OSX_$VERSION
if [ $runtime = "dotnet" ] ; then
./7za.exe a Radarr_Windows_$VERSION.zip ./Radarr_Windows_$VERSION/*
./7za.exe a -ttar -so Radarr_Mono_$VERSION.tar ./Radarr_Mono_$VERSION/* | ./7za.exe a -si Radarr_Mono_$VERSION.tar.gz
./7za.exe a -ttar -so Radarr_OSX_$VERSION.tar ./_output_osx/* | ./7za.exe a -si Radarr_OSX_$VERSION.tar.gz
./7za.exe a -ttar -so Radarr_OSX_App_$VERSION.tar ./_output_osx_app/* | ./7za.exe a -si Radarr_OSX_App_$VERSION.tar.gz
else
zip -r Radarr_Windows_$VERSION.zip Radarr_Windows_$VERSION/* >& /dev/null
zip -r Radarr_Mono_$VERSION.zip Radarr_Mono_$VERSION/* >& /dev/null #TODO update for tar.gz
zip -r Radarr_OSX_$VERSION_App.zip Radarr_OSX_$VERSION/* >& /dev/null
fi
ftp -n ftp.leonardogalli.ch << END_SCRIPT
passive
quote USER $FTP_USER
quote PASS $FTP_PASS
mkdir builds
cd builds
mkdir $YEAR
cd $YEAR
mkdir $MONTH
cd $MONTH
mkdir $DAY
cd $DAY
binary
put Radarr_Windows_$VERSION.zip
put Radarr_Mono_$VERSION.zip
put Radarr_OSX_$VERSION.zip
quit
END_SCRIPT

Binary file not shown.

View File

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

View File

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

View File

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

View File

@@ -43,9 +43,9 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -281,4 +281,4 @@
<Target Name="BeforeBuild">
</Target>
-->
</Project>
</Project>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net40" />
</packages>

View File

@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
namespace Microsoft.AspNet.SignalR.Owin

View File

@@ -21,3 +21,4 @@ using System.Runtime.InteropServices;
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("260b2ff9-d3b7-4d8a-b720-a12c93d045e5")]
[assembly: AssemblyVersion("10.0.0.*")]

View File

@@ -33,12 +33,12 @@ namespace NzbDrone.Api.Authentication
{
if (_configFileProvider.AuthenticationMethod == AuthenticationType.Forms)
{
RegisterFormsAuth(pipelines);
RegisterFormsAuth(pipelines);
}
else if (_configFileProvider.AuthenticationMethod == AuthenticationType.Basic)
{
pipelines.EnableBasicAuthentication(new BasicAuthenticationConfiguration(_authenticationService, "Radarr"));
pipelines.EnableBasicAuthentication(new BasicAuthenticationConfiguration(_authenticationService, "Sonarr"));
}
pipelines.BeforeRequest.AddItemToEndOfPipeline((Func<NancyContext, Response>) RequiresAuthentication);
@@ -64,8 +64,6 @@ namespace NzbDrone.Api.Authentication
new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt)))
);
FormsAuthentication.FormsAuthenticationCookieName = "_ncfaradarr"; //For those people that both have sonarr and radarr.
FormsAuthentication.Enable(pipelines, new FormsAuthenticationConfiguration
{
RedirectUrl = _configFileProvider.UrlBase + "/login",

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using NzbDrone.Api.Movie;
using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
@@ -12,14 +11,13 @@ namespace NzbDrone.Api.Blacklist
{
public int SeriesId { get; set; }
public List<int> EpisodeIds { get; set; }
public int MovieId { get; set; }
public string SourceTitle { get; set; }
public QualityModel Quality { get; set; }
public DateTime Date { get; set; }
public DownloadProtocol Protocol { get; set; }
public string Indexer { get; set; }
public string Message { get; set; }
public MovieResource Movie { get; set; }
public SeriesResource Series { get; set; }
}
@@ -32,7 +30,7 @@ namespace NzbDrone.Api.Blacklist
return new BlacklistResource
{
Id = model.Id,
MovieId = model.MovieId,
SeriesId = model.SeriesId,
EpisodeIds = model.EpisodeIds,
SourceTitle = model.SourceTitle,
@@ -41,7 +39,7 @@ namespace NzbDrone.Api.Blacklist
Protocol = model.Protocol,
Indexer = model.Indexer,
Message = model.Message,
Movie = model.Movie.ToResource(),
Series = model.Series.ToResource()
};
}

View File

@@ -16,18 +16,17 @@ namespace NzbDrone.Api.Calendar
{
public class CalendarFeedModule : NzbDroneFeedModule
{
private readonly IMovieService _movieService;
private readonly IEpisodeService _episodeService;
private readonly ITagService _tagService;
public CalendarFeedModule(IMovieService movieService, ITagService tagService)
public CalendarFeedModule(IEpisodeService episodeService, ITagService tagService)
: base("calendar")
{
_movieService = movieService;
_episodeService = episodeService;
_tagService = tagService;
Get["/NzbDrone.ics"] = options => GetCalendarFeed();
Get["/Sonarr.ics"] = options => GetCalendarFeed();
Get["/Radarr.ics"] = options => GetCalendarFeed();
}
private Response GetCalendarFeed()
@@ -37,7 +36,8 @@ namespace NzbDrone.Api.Calendar
var start = DateTime.Today.AddDays(-pastDays);
var end = DateTime.Today.AddDays(futureDays);
var unmonitored = false;
//var premiersOnly = 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,7 +46,8 @@ namespace NzbDrone.Api.Calendar
var queryPastDays = Request.Query.PastDays;
var queryFutureDays = Request.Query.FutureDays;
var queryUnmonitored = Request.Query.Unmonitored;
// var queryPremiersOnly = Request.Query.PremiersOnly;
var queryPremiersOnly = Request.Query.PremiersOnly;
var queryAsAllDay = Request.Query.AsAllDay;
var queryTags = Request.Query.Tags;
if (queryStart.HasValue) start = DateTime.Parse(queryStart.Value);
@@ -69,10 +70,15 @@ namespace NzbDrone.Api.Calendar
unmonitored = bool.Parse(queryUnmonitored.Value);
}
//if (queryPremiersOnly.HasValue)
//{
// premiersOnly = bool.Parse(queryPremiersOnly.Value);
//}
if (queryPremiersOnly.HasValue)
{
premiersOnly = bool.Parse(queryPremiersOnly.Value);
}
if (queryAsAllDay.HasValue)
{
asAllDay = bool.Parse(queryAsAllDay.Value);
}
if (queryTags.HasValue)
{
@@ -80,56 +86,51 @@ namespace NzbDrone.Api.Calendar
tags.AddRange(tagInput.Split(',').Select(_tagService.GetTag).Select(t => t.Id));
}
var movies = _movieService.GetMoviesBetweenDates(start, end, unmonitored);
var episodes = _episodeService.EpisodesBetweenDates(start, end, unmonitored);
var calendar = new Ical.Net.Calendar
{
ProductId = "-//radarr.video//Radarr//EN"
ProductId = "-//sonarr.tv//Sonarr//EN"
};
foreach (var movie in movies.OrderBy(v => v.Added))
foreach (var episode in episodes.OrderBy(v => v.AirDateUtc.Value))
{
if (tags.Any() && tags.None(movie.Tags.Contains))
if (premiersOnly && (episode.SeasonNumber == 0 || episode.EpisodeNumber != 1))
{
continue;
}
if (tags.Any() && tags.None(episode.Series.Tags.Contains))
{
continue;
}
var occurrence = calendar.Create<Event>();
occurrence.Uid = "NzbDrone_movie_" + movie.Id;
occurrence.Status = movie.HasFile ? EventStatus.Confirmed : EventStatus.Tentative;
occurrence.Uid = "NzbDrone_episode_" + episode.Id;
occurrence.Status = episode.HasFile ? EventStatus.Confirmed : EventStatus.Tentative;
occurrence.Description = episode.Overview;
occurrence.Categories = new List<string>() { episode.Series.Network };
switch (movie.Status)
if (asAllDay)
{
case MovieStatusType.PreDB:
if (movie.PhysicalRelease != null)
{
occurrence.Start = new CalDateTime(movie.PhysicalRelease.Value) { HasTime = true };
occurrence.End = new CalDateTime(movie.PhysicalRelease.Value.AddMinutes(movie.Runtime)) { HasTime = true };
}
break;
case MovieStatusType.InCinemas:
if (movie.InCinemas != null)
{
occurrence.Start = new CalDateTime(movie.InCinemas.Value) { HasTime = true };
occurrence.End = new CalDateTime(movie.InCinemas.Value.AddMinutes(movie.Runtime)) { HasTime = true };
}
break;
case MovieStatusType.Announced:
continue; // no date
default:
if (movie.PhysicalRelease != null)
{
occurrence.Start = new CalDateTime(movie.PhysicalRelease.Value) { HasTime = true };
occurrence.End = new CalDateTime(movie.PhysicalRelease.Value.AddMinutes(movie.Runtime)) { HasTime = true };
}
break;
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 };
}
occurrence.Description = movie.Overview;
occurrence.Categories = new List<string>() { movie.Studio };
occurrence.Summary = $"{movie.Title}";
switch (episode.Series.SeriesType)
{
case SeriesTypes.Daily:
occurrence.Summary = $"{episode.Series.Title} - {episode.Title}";
break;
default:
occurrence.Summary =$"{episode.Series.Title} - {episode.SeasonNumber}x{episode.EpisodeNumber:00} - {episode.Title}";
break;
}
}
var serializer = (IStringSerializer) new SerializerFactory().Build(calendar.GetType(), new SerializationContext());

View File

@@ -1,41 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Series;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MovieStats;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Validation;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Calendar
{
public class CalendarModule : MovieModule
public class CalendarModule : EpisodeModuleWithSignalR
{
public CalendarModule(IBroadcastSignalRMessage signalR,
IMovieService moviesService,
IMovieStatisticsService moviesStatisticsService,
ISceneMappingService sceneMappingService,
IMapCoversToLocal coverMapper)
: base(signalR, moviesService, moviesStatisticsService, sceneMappingService, coverMapper, "calendar")
public CalendarModule(IEpisodeService episodeService,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "calendar")
{
GetResourceAll = GetCalendar;
}
private List<MovieResource> GetCalendar()
private List<EpisodeResource> GetCalendar()
{
var start = DateTime.Today;
var end = DateTime.Today.AddDays(2);
@@ -49,9 +33,9 @@ namespace NzbDrone.Api.Calendar
if (queryEnd.HasValue) end = DateTime.Parse(queryEnd.Value);
if (queryIncludeUnmonitored.HasValue) includeUnmonitored = Convert.ToBoolean(queryIncludeUnmonitored.Value);
var resources = _moviesService.GetMoviesBetweenDates(start, end, includeUnmonitored).Select(MapToResource);
var resources = MapToResource(_episodeService.EpisodesBetweenDates(start, end, includeUnmonitored), true, true);
return resources.OrderBy(e => e.InCinemas).ToList();
return resources.OrderBy(e => e.AirDateUtc).ToList();
}
}
}

View File

@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Reflection;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Profiles;
namespace NzbDrone.Api.ClientSchema
{
@@ -150,18 +147,6 @@ namespace NzbDrone.Api.ClientSchema
private static List<SelectOption> GetSelectOptions(Type selectOptions)
{
if (selectOptions == typeof(Profile))
{
return new List<SelectOption>();
}
if (selectOptions == typeof(Quality))
{
var qOptions = from Quality q in selectOptions.GetProperties(BindingFlags.Static | BindingFlags.Public)
select new SelectOption {Name = q.Name, Value = q.Id};
return qOptions.OrderBy(o => o.Value).ToList();
}
var options = from Enum e in Enum.GetValues(selectOptions)
select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() };

View File

@@ -12,13 +12,13 @@ namespace NzbDrone.Api.Config
MappedNetworkDriveValidator mappedNetworkDriveValidator)
: base(configService)
{
SharedValidator.RuleFor(c => c.DownloadedMoviesFolder)
SharedValidator.RuleFor(c => c.DownloadedEpisodesFolder)
.Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(mappedNetworkDriveValidator)
.SetValidator(pathExistsValidator)
.When(c => !string.IsNullOrWhiteSpace(c.DownloadedMoviesFolder));
.When(c => !string.IsNullOrWhiteSpace(c.DownloadedEpisodesFolder));
}
protected override DownloadClientConfigResource ToResource(IConfigService model)

View File

@@ -5,9 +5,9 @@ namespace NzbDrone.Api.Config
{
public class DownloadClientConfigResource : RestResource
{
public string DownloadedMoviesFolder { get; set; }
public string DownloadedEpisodesFolder { get; set; }
public string DownloadClientWorkingFolders { get; set; }
public int DownloadedMoviesScanInterval { get; set; }
public int DownloadedEpisodesScanInterval { get; set; }
public bool EnableCompletedDownloadHandling { get; set; }
public bool RemoveCompletedDownloads { get; set; }
@@ -22,9 +22,9 @@ namespace NzbDrone.Api.Config
{
return new DownloadClientConfigResource
{
DownloadedMoviesFolder = model.DownloadedMoviesFolder,
DownloadedEpisodesFolder = model.DownloadedEpisodesFolder,
DownloadClientWorkingFolders = model.DownloadClientWorkingFolders,
DownloadedMoviesScanInterval = model.DownloadedMoviesScanInterval,
DownloadedEpisodesScanInterval = model.DownloadedEpisodesScanInterval,
EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling,
RemoveCompletedDownloads = model.RemoveCompletedDownloads,

View File

@@ -8,7 +8,6 @@ namespace NzbDrone.Api.Config
public int MinimumAge { get; set; }
public int Retention { get; set; }
public int RssSyncInterval { get; set; }
public int AvailabilityDelay { get; set; }
}
public static class IndexerConfigResourceMapper
@@ -20,7 +19,6 @@ namespace NzbDrone.Api.Config
MinimumAge = model.MinimumAge,
Retention = model.Retention,
RssSyncInterval = model.RssSyncInterval,
AvailabilityDelay = model.AvailabilityDelay,
};
}
}

View File

@@ -34,13 +34,11 @@ namespace NzbDrone.Api.Config
Get["/samples"] = x => GetExamples(this.Bind<NamingConfigResource>());
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 5);
/*SharedValidator.RuleFor(c => c.StandardEpisodeFormat).ValidEpisodeFormat();
SharedValidator.RuleFor(c => c.StandardEpisodeFormat).ValidEpisodeFormat();
SharedValidator.RuleFor(c => c.DailyEpisodeFormat).ValidDailyEpisodeFormat();
SharedValidator.RuleFor(c => c.AnimeEpisodeFormat).ValidAnimeEpisodeFormat();
SharedValidator.RuleFor(c => c.SeriesFolderFormat).ValidSeriesFolderFormat();
SharedValidator.RuleFor(c => c.SeasonFolderFormat).ValidSeasonFolderFormat();*/
SharedValidator.RuleFor(c => c.StandardMovieFormat).ValidMovieFormat();
SharedValidator.RuleFor(c => c.MovieFolderFormat).ValidMovieFolderFormat();
SharedValidator.RuleFor(c => c.SeasonFolderFormat).ValidSeasonFolderFormat();
}
private void UpdateNamingConfig(NamingConfigResource resource)
@@ -56,13 +54,7 @@ namespace NzbDrone.Api.Config
var nameSpec = _namingConfigService.GetConfig();
var resource = nameSpec.ToResource();
//if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
//{
// var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
// basicConfig.AddToResource(resource);
//}
if (resource.StandardMovieFormat.IsNotNullOrWhiteSpace())
if (resource.StandardEpisodeFormat.IsNotNullOrWhiteSpace())
{
var basicConfig = _filenameBuilder.GetBasicNamingConfig(nameSpec);
basicConfig.AddToResource(resource);
@@ -81,50 +73,39 @@ namespace NzbDrone.Api.Config
var nameSpec = config.ToModel();
var sampleResource = new NamingSampleResource();
//var singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec);
//var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec);
//var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec);
//var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
//var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec);
var singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec);
var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec);
var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec);
var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec);
var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec);
sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
? "Invalid format"
: singleEpisodeSampleResult.FileName;
//sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
// ? "Invalid format"
// : singleEpisodeSampleResult.FileName;
sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null
? "Invalid format"
: multiEpisodeSampleResult.FileName;
//sampleResource.MultiEpisodeExample = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult) != null
// ? "Invalid format"
// : multiEpisodeSampleResult.FileName;
sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null
? "Invalid format"
: dailyEpisodeSampleResult.FileName;
//sampleResource.DailyEpisodeExample = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult) != null
// ? "Invalid format"
// : dailyEpisodeSampleResult.FileName;
sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
? "Invalid format"
: animeEpisodeSampleResult.FileName;
//sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
// ? "Invalid format"
// : animeEpisodeSampleResult.FileName;
sampleResource.AnimeMultiEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult) != null
? "Invalid format"
: animeMultiEpisodeSampleResult.FileName;
//sampleResource.AnimeMultiEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult) != null
// ? "Invalid format"
// : animeMultiEpisodeSampleResult.FileName;
sampleResource.MovieExample = nameSpec.StandardMovieFormat.IsNullOrWhiteSpace()
? "Invalid Format"
: movieSampleResult.FileName;
//sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace()
// ? "Invalid format"
// : _filenameSampleService.GetSeriesFolderSample(nameSpec);
//sampleResource.SeasonFolderExample = nameSpec.SeasonFolderFormat.IsNullOrWhiteSpace()
// ? "Invalid format"
// : _filenameSampleService.GetSeasonFolderSample(nameSpec);
sampleResource.MovieFolderExample = nameSpec.MovieFolderFormat.IsNullOrWhiteSpace()
sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace()
? "Invalid format"
: _filenameSampleService.GetMovieFolderSample(nameSpec);
: _filenameSampleService.GetSeriesFolderSample(nameSpec);
sampleResource.SeasonFolderExample = nameSpec.SeasonFolderFormat.IsNullOrWhiteSpace()
? "Invalid format"
: _filenameSampleService.GetSeasonFolderSample(nameSpec);
return sampleResource.AsResponse();
}
@@ -137,25 +118,19 @@ namespace NzbDrone.Api.Config
var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
var animeMultiEpisodeSampleResult = _filenameSampleService.GetAnimeMultiEpisodeSample(nameSpec);
var movieSampleResult = _filenameSampleService.GetMovieSample(nameSpec);
var singleEpisodeValidationResult = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult);
var multiEpisodeValidationResult = _filenameValidationService.ValidateStandardFilename(multiEpisodeSampleResult);
var dailyEpisodeValidationResult = _filenameValidationService.ValidateDailyFilename(dailyEpisodeSampleResult);
var animeEpisodeValidationResult = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult);
var animeMultiEpisodeValidationResult = _filenameValidationService.ValidateAnimeFilename(animeMultiEpisodeSampleResult);
//var standardMovieValidationResult = _filenameValidationService.ValidateMovieFilename(movieSampleResult); For now, let's hope the user is not stupid enough :/
var validationFailures = new List<ValidationFailure>();
//validationFailures.AddIfNotNull(singleEpisodeValidationResult);
//validationFailures.AddIfNotNull(multiEpisodeValidationResult);
//validationFailures.AddIfNotNull(dailyEpisodeValidationResult);
//validationFailures.AddIfNotNull(animeEpisodeValidationResult);
//validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult);
//validationFailures.AddIfNotNull(standardMovieValidationResult);
validationFailures.AddIfNotNull(singleEpisodeValidationResult);
validationFailures.AddIfNotNull(multiEpisodeValidationResult);
validationFailures.AddIfNotNull(dailyEpisodeValidationResult);
validationFailures.AddIfNotNull(animeEpisodeValidationResult);
validationFailures.AddIfNotNull(animeMultiEpisodeValidationResult);
if (validationFailures.Any())
{

View File

@@ -7,8 +7,6 @@ namespace NzbDrone.Api.Config
{
public bool RenameEpisodes { get; set; }
public bool ReplaceIllegalCharacters { get; set; }
public string StandardMovieFormat { get; set; }
public string MovieFolderFormat { get; set; }
public int MultiEpisodeStyle { get; set; }
public string StandardEpisodeFormat { get; set; }
public string DailyEpisodeFormat { get; set; }
@@ -38,9 +36,7 @@ namespace NzbDrone.Api.Config
DailyEpisodeFormat = model.DailyEpisodeFormat,
AnimeEpisodeFormat = model.AnimeEpisodeFormat,
SeriesFolderFormat = model.SeriesFolderFormat,
SeasonFolderFormat = model.SeasonFolderFormat,
StandardMovieFormat = model.StandardMovieFormat,
MovieFolderFormat = model.MovieFolderFormat
SeasonFolderFormat = model.SeasonFolderFormat
//IncludeSeriesTitle
//IncludeEpisodeTitle
//IncludeQuality
@@ -68,14 +64,12 @@ namespace NzbDrone.Api.Config
RenameEpisodes = resource.RenameEpisodes,
ReplaceIllegalCharacters = resource.ReplaceIllegalCharacters,
//MultiEpisodeStyle = resource.MultiEpisodeStyle,
//StandardEpisodeFormat = resource.StandardEpisodeFormat,
//DailyEpisodeFormat = resource.DailyEpisodeFormat,
//AnimeEpisodeFormat = resource.AnimeEpisodeFormat,
//SeriesFolderFormat = resource.SeriesFolderFormat,
//SeasonFolderFormat = resource.SeasonFolderFormat,
StandardMovieFormat = resource.StandardMovieFormat,
MovieFolderFormat = resource.MovieFolderFormat
MultiEpisodeStyle = resource.MultiEpisodeStyle,
StandardEpisodeFormat = resource.StandardEpisodeFormat,
DailyEpisodeFormat = resource.DailyEpisodeFormat,
AnimeEpisodeFormat = resource.AnimeEpisodeFormat,
SeriesFolderFormat = resource.SeriesFolderFormat,
SeasonFolderFormat = resource.SeasonFolderFormat
};
}
}

View File

@@ -9,8 +9,5 @@
public string AnimeMultiEpisodeExample { get; set; }
public string SeriesFolderExample { get; set; }
public string SeasonFolderExample { get; set; }
public string MovieExample { get; set; }
public string MovieFolderExample { get; set; }
}
}

View File

@@ -1,22 +0,0 @@
using FluentValidation;
using NzbDrone.Api.Validation;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Config
{
public class NetImportConfigModule : NzbDroneConfigModule<NetImportConfigResource>
{
public NetImportConfigModule(IConfigService configService)
: base(configService)
{
SharedValidator.RuleFor(c => c.NetImportSyncInterval)
.IsValidNetImportSyncInterval();
}
protected override NetImportConfigResource ToResource(IConfigService model)
{
return NetImportConfigResourceMapper.ToResource(model);
}
}
}

View File

@@ -1,31 +0,0 @@
using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Config
{
public class NetImportConfigResource : RestResource
{
public int NetImportSyncInterval { get; set; }
public string ListSyncLevel { get; set; }
public string ImportExclusions { get; set; }
public string TraktAuthToken { get; set; }
public string TraktRefreshToken { get; set; }
public int TraktTokenExpiry { get; set; }
}
public static class NetImportConfigResourceMapper
{
public static NetImportConfigResource ToResource(IConfigService model)
{
return new NetImportConfigResource
{
NetImportSyncInterval = model.NetImportSyncInterval,
ListSyncLevel = model.ListSyncLevel,
ImportExclusions = model.ImportExclusions,
TraktAuthToken = model.TraktAuthToken,
TraktRefreshToken = model.TraktRefreshToken,
TraktTokenExpiry = model.TraktTokenExpiry,
};
}
}
}

View File

@@ -71,7 +71,7 @@ namespace NzbDrone.Api.EpisodeFiles
private void DeleteEpisodeFile(int id)
{
var episodeFile = _mediaFileService.Get(id);
var episodeFile = _mediaFileService.Get(id);
var series = _seriesService.GetSeries(episodeFile.SeriesId);
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);

View File

@@ -3,7 +3,6 @@ using NzbDrone.Api.REST;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR;
using Nancy;
namespace NzbDrone.Api.Episodes
{

View File

@@ -63,18 +63,16 @@ namespace NzbDrone.Api.ErrorManagement
}.AsResponse(HttpStatusCode.Conflict);
}
var sqlErrorMessage = string.Format("[{0} {1}]", context.Request.Method, context.Request.Path);
_logger.Error(sqLiteException, sqlErrorMessage);
_logger.Error(sqLiteException, "[{0} {1}]", context.Request.Method, context.Request.Path);
}
_logger.Fatal(exception, "Request Failed");
_logger.Fatal(exception, "Request Failed. {0} {1}", context.Request.Method, context.Request.Path);
return new ErrorModel
{
Message = exception.Message,
Description = exception.ToString()
}.AsResponse(HttpStatusCode.InternalServerError);
{
Message = exception.Message,
Description = exception.ToString()
}.AsResponse(HttpStatusCode.InternalServerError);
}
}
}

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;
@@ -66,9 +66,13 @@ namespace NzbDrone.Api.Extensions.Pipelines
private Response LogError(NancyContext context, Exception exception)
{
var response = _errorPipeline.HandleException(context, exception);
context.Response = response;
LogEnd(context);
context.Response = null;
return response;
}
@@ -78,7 +82,10 @@ namespace NzbDrone.Api.Extensions.Pipelines
{
return string.Concat(request.Url.Path, request.Url.Query);
}
return request.Url.Path;
else
{
return request.Url.Path;
}
}
}
}
}

View File

@@ -14,7 +14,7 @@ namespace NzbDrone.Api.Frontend
{
public bool IsCacheable(NancyContext context)
{
if (!RuntimeInfoBase.IsProduction)
if (!RuntimeInfo.IsProduction)
{
return false;
}

View File

@@ -25,7 +25,7 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return resourceUrl.StartsWith("/backup/") && resourceUrl.ContainsIgnoreCase("radarr_backup_") && resourceUrl.EndsWith(".zip");
return resourceUrl.StartsWith("/backup/") && resourceUrl.ContainsIgnoreCase("nzbdrone_backup_") && resourceUrl.EndsWith(".zip");
}
}
}

View File

@@ -74,7 +74,7 @@ namespace NzbDrone.Api.Frontend.Mappers
private string GetIndexText()
{
if (RuntimeInfoBase.IsProduction && _generatedContent != null)
if (RuntimeInfo.IsProduction && _generatedContent != null)
{
return _generatedContent;
}
@@ -106,7 +106,7 @@ namespace NzbDrone.Api.Frontend.Mappers
text = text.Replace("APP_BRANCH", _configFileProvider.Branch.ToLower());
text = text.Replace("APP_ANALYTICS", _analyticsService.IsEnabled.ToString().ToLowerInvariant());
text = text.Replace("URL_BASE", URL_BASE);
text = text.Replace("PRODUCTION", RuntimeInfoBase.IsProduction.ToString().ToLowerInvariant());
text = text.Replace("PRODUCTION", RuntimeInfo.IsProduction.ToString().ToLowerInvariant());
_generatedContent = text;

View File

@@ -67,7 +67,7 @@ namespace NzbDrone.Api.Frontend.Mappers
private string GetLoginText()
{
if (RuntimeInfoBase.IsProduction && _generatedContent != null)
if (RuntimeInfo.IsProduction && _generatedContent != null)
{
return _generatedContent;
}

View File

@@ -21,7 +21,7 @@ namespace NzbDrone.Api.Frontend.Mappers
_diskProvider = diskProvider;
_logger = logger;
if (!RuntimeInfoBase.IsProduction)
if (!RuntimeInfo.IsProduction)
{
_caseSensitive = StringComparison.OrdinalIgnoreCase;
}

View File

@@ -1,7 +1,8 @@
using System;
using Nancy;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Series;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
@@ -30,11 +31,13 @@ namespace NzbDrone.Api.History
protected HistoryResource MapToResource(Core.History.History model)
{
var resource = model.ToResource();
resource.Movie = model.Movie.ToResource();
if (model.Movie != null)
resource.Series = model.Series.ToResource();
resource.Episode = model.Episode.ToResource();
if (model.Series != null)
{
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Movie.Profile.Value, model.Quality);
resource.QualityCutoffNotMet = _qualityUpgradableSpecification.CutoffNotMet(model.Series.Profile.Value, model.Quality);
}
return resource;
@@ -42,7 +45,7 @@ namespace NzbDrone.Api.History
private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource)
{
var movieId = Request.Query.MovieId;
var episodeId = Request.Query.EpisodeId;
var pagingSpec = pagingResource.MapToPagingSpec<HistoryResource, Core.History.History>("date", SortDirection.Descending);
@@ -52,10 +55,10 @@ namespace NzbDrone.Api.History
pagingSpec.FilterExpression = v => v.EventType == filterValue;
}
if (movieId.HasValue)
if (episodeId.HasValue)
{
int i = (int)movieId;
pagingSpec.FilterExpression = h => h.MovieId == i;
int i = (int)episodeId;
pagingSpec.FilterExpression = h => h.EpisodeId == i;
}
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Api.Movie;
using NzbDrone.Core.History;
using NzbDrone.Core.Qualities;
@@ -13,7 +12,6 @@ namespace NzbDrone.Api.History
public class HistoryResource : RestResource
{
public int EpisodeId { get; set; }
public int MovieId { get; set; }
public int SeriesId { get; set; }
public string SourceTitle { get; set; }
public QualityModel Quality { get; set; }
@@ -24,7 +22,7 @@ namespace NzbDrone.Api.History
public HistoryEventType EventType { get; set; }
public Dictionary<string, string> Data { get; set; }
public MovieResource Movie { get; set; }
public EpisodeResource Episode { get; set; }
public SeriesResource Series { get; set; }
}
@@ -41,7 +39,6 @@ namespace NzbDrone.Api.History
EpisodeId = model.EpisodeId,
SeriesId = model.SeriesId,
MovieId = model.MovieId,
SourceTitle = model.SourceTitle,
Quality = model.Quality,
//QualityCutoffNotMet

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Api.Indexers
private readonly Logger _logger;
private readonly ICached<RemoteEpisode> _remoteEpisodeCache;
private readonly ICached<RemoteMovie> _remoteMovieCache;
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
ISearchForNzb nzbSearchService,
@@ -50,7 +49,6 @@ namespace NzbDrone.Api.Indexers
PostValidator.RuleFor(s => s.Guid).NotEmpty();
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
_remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies");
}
private Response DownloadRelease(ReleaseResource release)
@@ -61,26 +59,7 @@ namespace NzbDrone.Api.Indexers
{
_logger.Debug("Couldn't find requested release in cache, cache timeout probably expired.");
var remoteMovie = _remoteMovieCache.Find(release.Guid);
if (remoteMovie == null)
{
return new NotFoundResponse();
}
try
{
_downloadService.DownloadReport(remoteMovie);
}
catch (ReleaseDownloadException ex)
{
_logger.Error(ex, ex.Message);
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
}
return release.AsResponse();
return new NotFoundResponse();
}
try
@@ -89,7 +68,7 @@ namespace NzbDrone.Api.Indexers
}
catch (ReleaseDownloadException ex)
{
_logger.Error(ex, ex.Message);
_logger.Error(ex);
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
}
@@ -103,11 +82,6 @@ namespace NzbDrone.Api.Indexers
return GetEpisodeReleases(Request.Query.episodeId);
}
if (Request.Query.movieId != null)
{
return GetMovieReleases(Request.Query.movieId);
}
return GetRss();
}
@@ -122,28 +96,7 @@ namespace NzbDrone.Api.Indexers
}
catch (Exception ex)
{
_logger.Error(ex, "Episode search failed: " + ex.Message);
}
return new List<ReleaseResource>();
}
private List<ReleaseResource> GetMovieReleases(int movieId)
{
try
{
var decisions = _nzbSearchService.MovieSearch(movieId, true);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisionsForMovies(decisions);
return MapDecisions(prioritizedDecisions);
}
catch (NotImplementedException ex)
{
_logger.Error(ex, "One or more indexer you selected does not support movie search yet: " + ex.Message);
}
catch (Exception ex)
{
_logger.Error(ex, "Movie search failed: " + ex.Message);
_logger.Error(ex, "Episode search failed");
}
return new List<ReleaseResource>();
@@ -160,15 +113,7 @@ namespace NzbDrone.Api.Indexers
protected override ReleaseResource MapDecision(DownloadDecision decision, int initialWeight)
{
if (decision.IsForMovie)
{
_remoteMovieCache.Set(decision.RemoteMovie.Release.Guid, decision.RemoteMovie, TimeSpan.FromMinutes(30));
}
else
{
_remoteEpisodeCache.Set(decision.RemoteEpisode.Release.Guid, decision.RemoteEpisode, TimeSpan.FromMinutes(30));
}
_remoteEpisodeCache.Set(decision.RemoteEpisode.Release.Guid, decision.RemoteEpisode, TimeSpan.FromMinutes(30));
return base.MapDecision(decision, initialWeight);
}
}

View File

@@ -25,9 +25,9 @@ namespace NzbDrone.Api.Indexers
release.ReleaseWeight = initialWeight;
if (decision.RemoteMovie.Movie != null)
if (decision.RemoteEpisode.Series != null)
{
release.QualityWeight = decision.RemoteMovie.Movie
release.QualityWeight = decision.RemoteEpisode.Series
.Profile.Value
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
}

View File

@@ -24,7 +24,6 @@ namespace NzbDrone.Api.Indexers
public string Indexer { get; set; }
public string ReleaseGroup { get; set; }
public string ReleaseHash { get; set; }
public string Edition { get; set; }
public string Title { get; set; }
public bool FullSeason { get; set; }
public int SeasonNumber { get; set; }
@@ -87,60 +86,6 @@ namespace NzbDrone.Api.Indexers
var parsedEpisodeInfo = model.RemoteEpisode.ParsedEpisodeInfo;
var remoteEpisode = model.RemoteEpisode;
var torrentInfo = (model.RemoteEpisode.Release as TorrentInfo) ?? new TorrentInfo();
var downloadAllowed = model.RemoteEpisode.DownloadAllowed;
if (model.IsForMovie)
{
downloadAllowed = model.RemoteMovie.DownloadAllowed;
var parsedMovieInfo = model.RemoteMovie.ParsedMovieInfo;
return new ReleaseResource
{
Guid = releaseInfo.Guid,
Quality = parsedMovieInfo.Quality,
QualityWeight = parsedMovieInfo.Quality.Quality.Id, //Id kinda hacky for wheight, but what you gonna do? TODO: Fix this shit!
Age = releaseInfo.Age,
AgeHours = releaseInfo.AgeHours,
AgeMinutes = releaseInfo.AgeMinutes,
Size = releaseInfo.Size,
IndexerId = releaseInfo.IndexerId,
Indexer = releaseInfo.Indexer,
ReleaseGroup = parsedMovieInfo.ReleaseGroup,
ReleaseHash = parsedMovieInfo.ReleaseHash,
Title = releaseInfo.Title,
//FullSeason = parsedMovieInfo.FullSeason,
//SeasonNumber = parsedMovieInfo.SeasonNumber,
Language = parsedMovieInfo.Language,
AirDate = "",
SeriesTitle = parsedMovieInfo.MovieTitle,
EpisodeNumbers = new int[0],
AbsoluteEpisodeNumbers = new int[0],
Approved = model.Approved,
TemporarilyRejected = model.TemporarilyRejected,
Rejected = model.Rejected,
TvdbId = releaseInfo.TvdbId,
TvRageId = releaseInfo.TvRageId,
Rejections = model.Rejections.Select(r => r.Reason).ToList(),
PublishDate = releaseInfo.PublishDate,
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = downloadAllowed,
//ReleaseWeight
MagnetUrl = torrentInfo.MagnetUrl,
InfoHash = torrentInfo.InfoHash,
Seeders = torrentInfo.Seeders,
Leechers = (torrentInfo.Peers.HasValue && torrentInfo.Seeders.HasValue) ? (torrentInfo.Peers.Value - torrentInfo.Seeders.Value) : (int?)null,
Protocol = releaseInfo.DownloadProtocol,
Edition = parsedMovieInfo.Edition,
IsDaily = false,
IsAbsoluteNumbering = false,
IsPossibleSpecialEpisode = false,
//Special = parsedMovieInfo.Special,
};
}
// TODO: Clean this mess up. don't mix data from multiple classes, use sub-resources instead? (Got a huge Deja Vu, didn't we talk about this already once?)
return new ReleaseResource
@@ -174,7 +119,7 @@ namespace NzbDrone.Api.Indexers
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = downloadAllowed,
DownloadAllowed = remoteEpisode.DownloadAllowed,
//ReleaseWeight
MagnetUrl = torrentInfo.MagnetUrl,

View File

@@ -1,175 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Parser;
using System.Linq;
using System;
using Marr.Data;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.RootFolders;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Movie
{
public class UnmappedComparer : IComparer<UnmappedFolder>
{
public int Compare(UnmappedFolder a, UnmappedFolder b)
{
return a.Name.CompareTo(b.Name);
}
}
public class MovieBulkImportModule : NzbDroneRestModule<MovieResource>
{
private readonly ISearchForNewMovie _searchProxy;
private readonly IRootFolderService _rootFolderService;
private readonly IMakeImportDecision _importDecisionMaker;
private readonly IDiskScanService _diskScanService;
private readonly ICached<Core.Tv.Movie> _mappedMovies;
private readonly IMovieService _movieService;
public MovieBulkImportModule(ISearchForNewMovie searchProxy, IRootFolderService rootFolderService, IMakeImportDecision importDecisionMaker,
IDiskScanService diskScanService, ICacheManager cacheManager, IMovieService movieService)
: base("/movies/bulkimport")
{
_searchProxy = searchProxy;
_rootFolderService = rootFolderService;
_importDecisionMaker = importDecisionMaker;
_diskScanService = diskScanService;
_mappedMovies = cacheManager.GetCache<Core.Tv.Movie>(GetType(), "mappedMoviesCache");
_movieService = movieService;
Get["/"] = x => Search();
}
private Response Search()
{
if (Request.Query.Id == 0)
{
//Todo error handling
}
RootFolder rootFolder = _rootFolderService.Get(Request.Query.Id);
int page = Request.Query.page;
int per_page = Request.Query.per_page;
int min = (page - 1) * per_page;
int max = page * per_page;
var unmapped = rootFolder.UnmappedFolders.OrderBy(f => f.Name).ToList();
int total_count = unmapped.Count;
if (Request.Query.total_entries.HasValue)
{
total_count = Request.Query.total_entries;
}
max = total_count >= max ? max : total_count;
var paged = unmapped.GetRange(min, max-min);
var mapped = paged.Select(f =>
{
Core.Tv.Movie m = null;
var mappedMovie = _mappedMovies.Find(f.Name);
if (mappedMovie != null)
{
return mappedMovie;
}
var parsedTitle = Parser.ParseMoviePath(f.Name);
if (parsedTitle == null)
{
m = new Core.Tv.Movie
{
Title = f.Name.Replace(".", " ").Replace("-", " "),
Path = f.Path,
};
}
else
{
m = new Core.Tv.Movie
{
Title = parsedTitle.MovieTitle,
Year = parsedTitle.Year,
ImdbId = parsedTitle.ImdbId,
Path = f.Path
};
}
var files = _diskScanService.GetVideoFiles(f.Path);
var decisions = _importDecisionMaker.GetImportDecisions(files.ToList(), m, true);
var decision = decisions.Where(d => d.Approved && !d.Rejections.Any()).FirstOrDefault();
if (decision != null)
{
var local = decision.LocalMovie;
m.MovieFile = new LazyLoaded<MovieFile>(new MovieFile
{
Path = local.Path,
Edition = local.ParsedMovieInfo.Edition,
Quality = local.Quality,
MediaInfo = local.MediaInfo,
ReleaseGroup = local.ParsedMovieInfo.ReleaseGroup,
RelativePath = f.Path.GetRelativePath(local.Path)
});
}
mappedMovie = _searchProxy.MapMovieToTmdbMovie(m);
if (mappedMovie != null)
{
mappedMovie.Monitored = true;
_mappedMovies.Set(f.Name, mappedMovie, TimeSpan.FromDays(2));
return mappedMovie;
}
return null;
});
return new PagingResource<MovieResource>
{
Page = page,
PageSize = per_page,
SortDirection = SortDirection.Ascending,
SortKey = Request.Query.sort_by,
TotalRecords = total_count - mapped.Where(m => m == null).Count(),
Records = MapToResource(mapped.Where(m => m != null)).ToList()
}.AsResponse();
}
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
{
foreach (var currentMovie in movies)
{
var resource = currentMovie.ToResource();
var poster = currentMovie.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null)
{
resource.RemotePoster = poster.Url;
}
yield return resource;
}
}
}
}

View File

@@ -1,31 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Movie
{
public class MovieEditorModule : NzbDroneApiModule
{
private readonly IMovieService _movieService;
public MovieEditorModule(IMovieService movieService)
: base("/movie/editor")
{
_movieService = movieService;
Put["/"] = Movie => SaveAll();
}
private Response SaveAll()
{
var resources = Request.Body.FromJson<List<MovieResource>>();
var Movie = resources.Select(MovieResource => MovieResource.ToModel(_movieService.GetMovie(MovieResource.Id))).ToList();
return _movieService.UpdateMovie(Movie)
.ToResource()
.AsResponse(HttpStatusCode.Accepted);
}
}
}

View File

@@ -1,72 +0,0 @@
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Api.REST;
using NzbDrone.Api.Movie;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR;
namespace NzbDrone.Api.EpisodeFiles
{
public class MovieFileModule : NzbDroneRestModuleWithSignalR<MovieFileResource, MovieFile>, IHandle<MovieFileAddedEvent>
{
private readonly IMediaFileService _mediaFileService;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IMovieService _movieService;
private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly Logger _logger;
public MovieFileModule(IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService,
IRecycleBinProvider recycleBinProvider,
IMovieService movieService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
Logger logger)
: base(signalRBroadcaster)
{
_mediaFileService = mediaFileService;
_recycleBinProvider = recycleBinProvider;
_movieService = movieService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
_logger = logger;
GetResourceById = GetMovieFile;
UpdateResource = SetQuality;
DeleteResource = DeleteMovieFile;
}
private MovieFileResource GetMovieFile(int id)
{
var movie = _mediaFileService.GetMovie(id);
return movie.ToResource();
}
private void SetQuality(MovieFileResource movieFileResource)
{
var movieFile = _mediaFileService.GetMovie(movieFileResource.Id);
movieFile.Quality = movieFileResource.Quality;
_mediaFileService.Update(movieFile);
}
private void DeleteMovieFile(int id)
{
var movieFile = _mediaFileService.GetMovie(id);
var movie = _movieService.GetMovie(movieFile.MovieId);
var fullPath = Path.Combine(movie.Path, movieFile.RelativePath);
_logger.Info("Deleting movie file: {0}", fullPath);
_recycleBinProvider.DeleteFile(fullPath);
_mediaFileService.Delete(movieFile, DeleteMediaFileReason.Manual);
}
public void Handle(MovieFileAddedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.MovieFile.Id);
}
}
}

View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Api.Movies
{
class MovieModule
{
}
}

View File

@@ -1,78 +0,0 @@
using NzbDrone.Api.Movie;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Movies
{
public abstract class MovieModuleWithSignalR : NzbDroneRestModuleWithSignalR<MovieResource, Core.Tv.Movie>,
IHandle<MovieGrabbedEvent>,
IHandle<MovieDownloadedEvent>
{
protected readonly IMovieService _movieService;
protected readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
protected MovieModuleWithSignalR(IMovieService movieService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(signalRBroadcaster)
{
_movieService = movieService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetMovie;
}
protected MovieModuleWithSignalR(IMovieService movieService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster,
string resource)
: base(signalRBroadcaster, resource)
{
_movieService = movieService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetMovie;
}
protected MovieResource GetMovie(int id)
{
var movie = _movieService.GetMovie(id);
var resource = MapToResource(movie, true);
return resource;
}
protected MovieResource MapToResource(Core.Tv.Movie episode, bool includeSeries)
{
var resource = episode.ToResource();
if (includeSeries)
{
var series = episode ?? _movieService.GetMovie(episode.Id);
resource = series.ToResource();
}
return resource;
}
public void Handle(MovieGrabbedEvent message)
{
var resource = message.Movie.Movie.ToResource();
//add a grabbed field in MovieResource?
//resource.Grabbed = true;
BroadcastResourceChange(ModelAction.Updated, resource);
}
public void Handle(MovieDownloadedEvent message)
{
var resource = message.Movie.Movie.ToResource();
BroadcastResourceChange(ModelAction.Updated, resource);
}
}
}

View File

@@ -1,35 +0,0 @@
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaFiles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Api.Movies
{
public class RenameMovieModule : NzbDroneRestModule<RenameMovieResource>
{
private readonly IRenameMovieFileService _renameMovieFileService;
public RenameMovieModule(IRenameMovieFileService renameMovieFileService)
: base("renameMovie")
{
_renameMovieFileService = renameMovieFileService;
GetResourceAll = GetMovies; //TODO: GetResourceSingle?
}
private List<RenameMovieResource> GetMovies()
{
if(!Request.Query.MovieId.HasValue)
{
throw new BadRequestException("movieId is missing");
}
var movieId = (int)Request.Query.MovieId;
return _renameMovieFileService.GetRenamePreviews(movieId).ToResource();
}
}
}

View File

@@ -1,35 +0,0 @@
using NzbDrone.Api.REST;
using System.Collections.Generic;
using System.Linq;
namespace NzbDrone.Api.Movies
{
public class RenameMovieResource : RestResource
{
public int MovieId { get; set; }
public int MovieFileId { get; set; }
public string ExistingPath { get; set; }
public string NewPath { get; set; }
}
public static class RenameMovieResourceMapper
{
public static RenameMovieResource ToResource(this Core.MediaFiles.RenameMovieFilePreview model)
{
if (model == null) return null;
return new RenameMovieResource
{
MovieId = model.MovieId,
MovieFileId = model.MovieFileId,
ExistingPath = model.ExistingPath,
NewPath = model.NewPath
};
}
public static List<RenameMovieResource> ToResource(this IEnumerable<Core.MediaFiles.RenameMovieFilePreview> models)
{
return models.Select(ToResource).ToList();
}
}
}

View File

@@ -24,9 +24,9 @@ namespace NzbDrone.Api
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
Logger.Info("Starting NzbDrone API");
Logger.Info("Starting Web Server");
if (RuntimeInfoBase.IsProduction)
if (RuntimeInfo.IsProduction)
{
DiagnosticsHook.Disable(pipelines);
}

View File

@@ -1,34 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Nancy;
using Nancy.Extensions;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Movie;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.NetImport
{
public class ListImportModule : NzbDroneApiModule
{
private readonly IMovieService _movieService;
private readonly ISearchForNewMovie _movieSearch;
public ListImportModule(IMovieService movieService, ISearchForNewMovie movieSearch)
: base("/movie/import")
{
_movieService = movieService;
_movieSearch = movieSearch;
Put["/"] = Movie => SaveAll();
}
private Response SaveAll()
{
var resources = Request.Body.FromJson<List<MovieResource>>();
var Movies = resources.Select(MovieResource => _movieSearch.MapMovieToTmdbMovie(MovieResource.ToModel())).Where(m => m != null).DistinctBy(m => m.TmdbId).ToList();
return _movieService.AddMovies(Movies).ToResource().AsResponse(HttpStatusCode.Accepted);
}
}
}

View File

@@ -1,47 +0,0 @@
using FluentValidation;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.NetImport;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.NetImport
{
public class NetImportModule : ProviderModuleBase<NetImportResource, INetImport, NetImportDefinition>
{
public NetImportModule(NetImportFactory netImportFactory) : base(netImportFactory, "netimport")
{
PostValidator.RuleFor(c => c.RootFolderPath).NotNull();
PostValidator.RuleFor(c => c.MinimumAvailability).NotNull();
PostValidator.RuleFor(c => c.ProfileId).NotNull();
}
protected override void MapToResource(NetImportResource resource, NetImportDefinition definition)
{
base.MapToResource(resource, definition);
resource.Enabled = definition.Enabled;
resource.EnableAuto = definition.EnableAuto;
resource.ProfileId = definition.ProfileId;
resource.RootFolderPath = definition.RootFolderPath;
resource.ShouldMonitor = definition.ShouldMonitor;
resource.MinimumAvailability = definition.MinimumAvailability;
}
protected override void MapToModel(NetImportDefinition definition, NetImportResource resource)
{
base.MapToModel(definition, resource);
definition.Enabled = resource.Enabled;
definition.EnableAuto = resource.EnableAuto;
definition.ProfileId = resource.ProfileId;
definition.RootFolderPath = resource.RootFolderPath;
definition.ShouldMonitor = resource.ShouldMonitor;
definition.MinimumAvailability = resource.MinimumAvailability;
}
protected override void Validate(NetImportDefinition definition, bool includeWarnings)
{
if (!definition.Enable) return;
base.Validate(definition, includeWarnings);
}
}
}

View File

@@ -1,15 +0,0 @@
using NzbDrone.Core.NetImport;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.NetImport
{
public class NetImportResource : ProviderResource
{
public bool Enabled { get; set; }
public bool EnableAuto { get; set; }
public bool ShouldMonitor { get; set; }
public string RootFolderPath { get; set; }
public int ProfileId { get; set; }
public MovieStatusType MinimumAvailability { get; set; }
}
}

View File

@@ -68,12 +68,12 @@
<HintPath>..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net40\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<HintPath>..\packages\NLog.4.4.1\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NodaTime, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4226afe0d9b296d1, processorArchitecture=MSIL">
@@ -109,8 +109,6 @@
<Compile Include="ClientSchema\SelectOption.cs" />
<Compile Include="Commands\CommandModule.cs" />
<Compile Include="Commands\CommandResource.cs" />
<Compile Include="Config\NetImportConfigModule.cs" />
<Compile Include="Config\NetImportConfigResource.cs" />
<Compile Include="Extensions\AccessControlHeaders.cs" />
<Compile Include="Extensions\Pipelines\CorsPipeline.cs" />
<Compile Include="Extensions\Pipelines\RequestLoggingPipeline.cs" />
@@ -118,16 +116,6 @@
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
<Compile Include="Indexers\ReleaseModuleBase.cs" />
<Compile Include="Indexers\ReleasePushModule.cs" />
<Compile Include="Movies\MovieModuleWithSignalR.cs" />
<Compile Include="Movies\MovieBulkImportModule.cs" />
<Compile Include="Movies\MovieFileModule.cs" />
<Compile Include="Series\MovieModule.cs" />
<Compile Include="Movies\RenameMovieModule.cs" />
<Compile Include="Movies\RenameMovieResource.cs" />
<Compile Include="Movies\MovieEditorModule.cs" />
<Compile Include="NetImport\ListImportModule.cs" />
<Compile Include="NetImport\NetImportModule.cs" />
<Compile Include="NetImport\NetImportResource.cs" />
<Compile Include="Parse\ParseModule.cs" />
<Compile Include="Parse\ParseResource.cs" />
<Compile Include="ManualImport\ManualImportModule.cs" />
@@ -240,15 +228,11 @@
<Compile Include="RootFolders\RootFolderResource.cs" />
<Compile Include="SeasonPass\SeasonPassResource.cs" />
<Compile Include="Series\AlternateTitleResource.cs" />
<Compile Include="Series\MovieFileResource.cs" />
<Compile Include="Series\FetchMovieListModule.cs" />
<Compile Include="Series\SeasonResource.cs" />
<Compile Include="SeasonPass\SeasonPassModule.cs" />
<Compile Include="Series\SeriesEditorModule.cs" />
<Compile Include="Series\MovieLookupModule.cs" />
<Compile Include="Series\SeriesLookupModule.cs" />
<Compile Include="Series\SeriesModule.cs" />
<Compile Include="Series\MovieResource.cs" />
<Compile Include="Series\SeriesResource.cs" />
<Compile Include="Series\SeasonStatisticsResource.cs" />
<Compile Include="System\Backup\BackupModule.cs" />
@@ -261,15 +245,12 @@
<Compile Include="TinyIoCNancyBootstrapper.cs" />
<Compile Include="Update\UpdateModule.cs" />
<Compile Include="Update\UpdateResource.cs" />
<Compile Include="Validation\NetImportSyncIntervalValidator.cs" />
<Compile Include="Validation\RssSyncIntervalValidator.cs" />
<Compile Include="Validation\EmptyCollectionValidator.cs" />
<Compile Include="Validation\RuleBuilderExtensions.cs" />
<Compile Include="Wanted\CutoffModule.cs" />
<Compile Include="Wanted\LegacyMissingModule.cs" />
<Compile Include="Wanted\MissingModule.cs" />
<Compile Include="Wanted\MovieCutoffModule.cs" />
<Compile Include="Wanted\MovieMissingModule.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
@@ -297,11 +278,11 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Collections.Generic;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Api
@@ -13,7 +11,6 @@ namespace NzbDrone.Api
public SortDirection SortDirection { get; set; }
public string FilterKey { get; set; }
public string FilterValue { get; set; }
public string FilterType { get; set; }
public int TotalRecords { get; set; }
public List<TResource> Records { get; set; }
}
@@ -41,14 +38,5 @@ namespace NzbDrone.Api
return pagingSpec;
}
/*public static Expression<Func<TModel, object>> CreateFilterExpression<TModel>(string filterKey, string filterValue)
{
Type type = typeof(TModel);
ParameterExpression parameterExpression = Expression.Parameter(type, "x");
Expression expressionBody = parameterExpression;
return expressionBody;
}*/
}
}

View File

@@ -11,7 +11,6 @@ namespace NzbDrone.Api.Profiles
{
public string Name { get; set; }
public Quality Cutoff { get; set; }
public string PreferredTags { get; set; }
public List<ProfileQualityItemResource> Items { get; set; }
public Language Language { get; set; }
}
@@ -34,7 +33,6 @@ namespace NzbDrone.Api.Profiles
Name = model.Name,
Cutoff = model.Cutoff,
PreferredTags = model.PreferredTags != null ? string.Join(",", model.PreferredTags) : "",
Items = model.Items.ConvertAll(ToResource),
Language = model.Language
};
@@ -61,7 +59,6 @@ namespace NzbDrone.Api.Profiles
Name = resource.Name,
Cutoff = (Quality)resource.Cutoff.Id,
PreferredTags = resource.PreferredTags.Split(',').ToList(),
Items = resource.Items.ConvertAll(ToModel),
Language = resource.Language
};

View File

@@ -6,5 +6,6 @@ using System.Runtime.InteropServices;
[assembly: Guid("4c0922d7-979e-4ff7-b44b-b8ac2100eeb5")]
[assembly: AssemblyVersion("10.0.0.*")]
[assembly: InternalsVisibleTo("NzbDrone.Core")]

View File

@@ -119,7 +119,7 @@ namespace NzbDrone.Api
resource.Fields = SchemaBuilder.ToSchema(definition.Settings);
resource.InfoLink = string.Format("https://github.com/Radarr/Radarr/wiki/Supported-{0}#{1}",
resource.InfoLink = string.Format("https://github.com/Sonarr/Sonarr/wiki/Supported-{0}#{1}",
typeof(TProviderResource).Name.Replace("Resource", "s"),
definition.Implementation.ToLower());
}

View File

@@ -4,7 +4,6 @@ using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movie;
using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.Indexers;
using System.Linq;
@@ -15,7 +14,6 @@ namespace NzbDrone.Api.Queue
{
public SeriesResource Series { get; set; }
public EpisodeResource Episode { get; set; }
public MovieResource Movie { get; set; }
public QualityModel Quality { get; set; }
public decimal Size { get; set; }
public string Title { get; set; }
@@ -51,8 +49,7 @@ namespace NzbDrone.Api.Queue
TrackedDownloadStatus = model.TrackedDownloadStatus,
StatusMessages = model.StatusMessages,
DownloadId = model.DownloadId,
Protocol = model.Protocol,
Movie = model.Movie.ToResource()
Protocol = model.Protocol
};
}

View File

@@ -123,13 +123,7 @@ namespace NzbDrone.Api.REST
Get[ROOT_ROUTE] = options =>
{
var pagingSpec = ReadPagingResourceFromRequest();
if (pagingSpec.Page == 0 && pagingSpec.PageSize == 0)
{
var all = GetResourceAll();
return all.AsResponse();
}
var resource = GetResourcePaged(pagingSpec);
var resource = GetResourcePaged(ReadPagingResourceFromRequest());
return resource.AsResponse();
};
}
@@ -220,10 +214,12 @@ namespace NzbDrone.Api.REST
private PagingResource<TResource> ReadPagingResourceFromRequest()
{
int pageSize;
int.TryParse(Request.Query.PageSize.ToString(), out pageSize);
int.TryParse(Request.Query.PageSize.ToString(), out pageSize);
if (pageSize == 0) pageSize = 10;
int page;
int.TryParse(Request.Query.Page.ToString(), out page);
if (page == 0) page = 1;
var pagingResource = new PagingResource<TResource>
@@ -253,16 +249,9 @@ namespace NzbDrone.Api.REST
{
pagingResource.FilterValue = Request.Query.FilterValue.ToString();
}
if (Request.Query.FilterType != null)
{
pagingResource.FilterType = Request.Query.FilterType.ToString();
}
}
return pagingResource;
}
}
}
}

View File

@@ -38,8 +38,8 @@ namespace NzbDrone.Api.RootFolders
Id = resource.Id,
Path = resource.Path,
FreeSpace = resource.FreeSpace,
UnmappedFolders = resource.UnmappedFolders
//FreeSpace
//UnmappedFolders
};
}

View File

@@ -1,60 +0,0 @@
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource;
using System.Linq;
using NzbDrone.Core.NetImport;
namespace NzbDrone.Api.Movie
{
public class FetchMovieListModule : NzbDroneRestModule<MovieResource>
{
private readonly IFetchNetImport _fetchNetImport;
private readonly ISearchForNewMovie _movieSearch;
public FetchMovieListModule(IFetchNetImport netImport, ISearchForNewMovie movieSearch)
: base("/netimport/movies")
{
_fetchNetImport = netImport;
_movieSearch = movieSearch;
Get["/"] = x => Search();
}
private Response Search()
{
var results = _fetchNetImport.FetchAndFilter((int) Request.Query.listId, false);
List<Core.Tv.Movie> realResults = new List<Core.Tv.Movie>();
/*foreach (var movie in results)
{
var mapped = _movieSearch.MapMovieToTmdbMovie(movie);
if (mapped != null)
{
realResults.Add(mapped);
}
}*/
return MapToResource(results).AsResponse();
}
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
{
foreach (var currentSeries in movies)
{
var resource = currentSeries.ToResource();
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null)
{
resource.RemotePoster = poster.Url;
}
yield return resource;
}
}
}
}

View File

@@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Api.Movie
{
public class MovieFileResource : RestResource
{
public MovieFileResource()
{
}
//Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately
public int MovieId { get; set; }
public string RelativePath { get; set; }
public string Path { get; set; }
public long Size { get; set; }
public DateTime DateAdded { get; set; }
public string SceneName { get; set; }
public string ReleaseGroup { get; set; }
public QualityModel Quality { get; set; }
public MovieResource Movie { get; set; }
public string Edition { get; set; }
public Core.MediaFiles.MediaInfo.MediaInfoModel MediaInfo { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
}
public static class MovieFileResourceMapper
{
public static MovieFileResource ToResource(this MovieFile model)
{
if (model == null) return null;
MovieResource movie = null;
if (model.Movie != null)
{
model.Movie.LazyLoad();
if (model.Movie.Value != null)
{
//movie = model.Movie.Value.ToResource();
}
}
return new MovieFileResource
{
Id = model.Id,
RelativePath = model.RelativePath,
Path = model.Path,
Size = model.Size,
DateAdded = model.DateAdded,
ReleaseGroup = model.ReleaseGroup,
Quality = model.Quality,
Movie = movie,
MediaInfo = model.MediaInfo,
Edition = model.Edition
};
}
public static MovieFile ToModel(this MovieFileResource resource)
{
if (resource == null) return null;
return new MovieFile
{
};
}
public static List<MovieFileResource> ToResource(this IEnumerable<MovieFile> movies)
{
return movies.Select(ToResource).ToList();
}
}
}

View File

@@ -1,67 +0,0 @@
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource;
using System.Linq;
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Movie
{
public class MovieLookupModule : NzbDroneRestModule<MovieResource>
{
private readonly ISearchForNewMovie _searchProxy;
private readonly IProvideMovieInfo _movieInfo;
public MovieLookupModule(ISearchForNewMovie searchProxy, IProvideMovieInfo movieInfo)
: base("/movies/lookup")
{
_movieInfo = movieInfo;
_searchProxy = searchProxy;
Get["/"] = x => Search();
Get["/tmdb"] = x => SearchByTmdbId();
Get["/imdb"] = x => SearchByImdbId();
}
private Response SearchByTmdbId()
{
int tmdbId = -1;
if(Int32.TryParse(Request.Query.tmdbId, out tmdbId))
{
var result = _movieInfo.GetMovieInfo(tmdbId, null, true);
return result.ToResource().AsResponse();
}
throw new BadRequestException("Tmdb Id was not valid");
}
private Response SearchByImdbId()
{
string imdbId = Request.Query.imdbId;
var result = _movieInfo.GetMovieInfo(imdbId);
return result.ToResource().AsResponse();
}
private Response Search()
{
var imdbResults = _searchProxy.SearchForNewMovie((string)Request.Query.term);
return MapToResource(imdbResults).AsResponse();
}
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
{
foreach (var currentSeries in movies)
{
var resource = currentSeries.ToResource();
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null)
{
resource.RemotePoster = poster.Url;
}
yield return resource;
}
}
}
}

View File

@@ -1,275 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MovieStats;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Validation;
using NzbDrone.SignalR;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Api.Movie
{
public class MovieModule : NzbDroneRestModuleWithSignalR<MovieResource, Core.Tv.Movie>,
IHandle<EpisodeImportedEvent>,
IHandle<EpisodeFileDeletedEvent>,
IHandle<MovieUpdatedEvent>,
IHandle<MovieEditedEvent>,
IHandle<MovieDeletedEvent>,
IHandle<MovieRenamedEvent>,
IHandle<MediaCoversUpdatedEvent>
{
protected readonly IMovieService _moviesService;
private readonly IMovieStatisticsService _moviesStatisticsService;
private readonly IMapCoversToLocal _coverMapper;
private const string TITLE_SLUG_ROUTE = "/titleslug/(?<slug>[^/]+)";
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
IMovieService moviesService,
IMovieStatisticsService moviesStatisticsService,
ISceneMappingService sceneMappingService,
IMapCoversToLocal coverMapper,
RootFolderValidator rootFolderValidator,
MoviePathValidator moviesPathValidator,
MovieExistsValidator moviesExistsValidator,
DroneFactoryValidator droneFactoryValidator,
MovieAncestorValidator moviesAncestorValidator,
ProfileExistsValidator profileExistsValidator
)
: base(signalRBroadcaster)
{
_moviesService = moviesService;
_moviesStatisticsService = moviesStatisticsService;
_coverMapper = coverMapper;
GetResourceAll = AllMovie;
GetResourcePaged = GetMoviePaged;
GetResourceById = GetMovie;
Get[TITLE_SLUG_ROUTE] = (options) => {
return ReqResExtensions.AsResponse(GetByTitleSlug(options.slug));
};
CreateResource = AddMovie;
UpdateResource = UpdateMovie;
DeleteResource = DeleteMovie;
Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.ProfileId));
SharedValidator.RuleFor(s => s.Path)
.Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(moviesPathValidator)
.SetValidator(droneFactoryValidator)
.SetValidator(moviesAncestorValidator)
.When(s => !s.Path.IsNullOrWhiteSpace());
SharedValidator.RuleFor(s => s.ProfileId).SetValidator(profileExistsValidator);
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.TmdbId).NotNull().NotEmpty().SetValidator(moviesExistsValidator);
PutValidator.RuleFor(s => s.Path).IsValidPath();
}
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
IMovieService moviesService,
IMovieStatisticsService moviesStatisticsService,
ISceneMappingService sceneMappingService,
IMapCoversToLocal coverMapper,
string resource)
: base(signalRBroadcaster, resource)
{
_moviesService = moviesService;
_moviesStatisticsService = moviesStatisticsService;
_coverMapper = coverMapper;
GetResourceAll = AllMovie;
GetResourceById = GetMovie;
CreateResource = AddMovie;
UpdateResource = UpdateMovie;
DeleteResource = DeleteMovie;
}
private MovieResource GetMovie(int id)
{
var movies = _moviesService.GetMovie(id);
return MapToResource(movies);
}
private PagingResource<MovieResource> GetMoviePaged(PagingResource<MovieResource> pagingResource)
{
var pagingSpec = pagingResource.MapToPagingSpec<MovieResource, Core.Tv.Movie>();
pagingSpec.FilterExpression = _moviesService.ConstructFilterExpression(pagingResource.FilterKey, pagingResource.FilterValue, pagingResource.FilterType);
return ApplyToPage(_moviesService.Paged, pagingSpec, MovieResourceMapper.ToResource);
}
protected MovieResource MapToResource(Core.Tv.Movie movies)
{
if (movies == null) return null;
var resource = movies.ToResource();
MapCoversToLocal(resource);
FetchAndLinkMovieStatistics(resource);
PopulateAlternateTitles(resource);
return resource;
}
private List<MovieResource> AllMovie()
{
var moviesStats = _moviesStatisticsService.MovieStatistics();
var moviesResources = _moviesService.GetAllMovies().ToResource();
MapCoversToLocal(moviesResources.ToArray());
LinkMovieStatistics(moviesResources, moviesStats);
PopulateAlternateTitles(moviesResources);
return moviesResources;
}
private MovieResource GetByTitleSlug(string slug)
{
return MapToResource(_moviesService.FindByTitleSlug(slug));
}
private int AddMovie(MovieResource moviesResource)
{
var model = moviesResource.ToModel();
return _moviesService.AddMovie(model).Id;
}
private void UpdateMovie(MovieResource moviesResource)
{
var model = moviesResource.ToModel(_moviesService.GetMovie(moviesResource.Id));
_moviesService.UpdateMovie(model);
BroadcastResourceChange(ModelAction.Updated, moviesResource);
}
private void DeleteMovie(int id)
{
var deleteFiles = false;
var addExclusion = false;
var deleteFilesQuery = Request.Query.deleteFiles;
var addExclusionQuery = Request.Query.addExclusion;
if (deleteFilesQuery.HasValue)
{
deleteFiles = Convert.ToBoolean(deleteFilesQuery.Value);
}
if (addExclusionQuery.HasValue)
{
addExclusion = Convert.ToBoolean(addExclusionQuery.Value);
}
_moviesService.DeleteMovie(id, deleteFiles, addExclusion);
}
private void MapCoversToLocal(params MovieResource[] movies)
{
foreach (var moviesResource in movies)
{
_coverMapper.ConvertToLocalUrls(moviesResource.Id, moviesResource.Images);
}
}
private void FetchAndLinkMovieStatistics(MovieResource resource)
{
LinkMovieStatistics(resource, _moviesStatisticsService.MovieStatistics(resource.Id));
}
private void LinkMovieStatistics(List<MovieResource> resources, List<MovieStatistics> moviesStatistics)
{
var dictMovieStats = moviesStatistics.ToDictionary(v => v.MovieId);
foreach (var movies in resources)
{
var stats = dictMovieStats.GetValueOrDefault(movies.Id);
if (stats == null) continue;
LinkMovieStatistics(movies, stats);
}
}
private void LinkMovieStatistics(MovieResource resource, MovieStatistics moviesStatistics)
{
resource.SizeOnDisk = moviesStatistics.SizeOnDisk;
}
private void PopulateAlternateTitles(List<MovieResource> resources)
{
foreach (var resource in resources)
{
PopulateAlternateTitles(resource);
}
}
private void PopulateAlternateTitles(MovieResource resource)
{
//var mappings = null;//_sceneMappingService.FindByTvdbId(resource.TvdbId);
//if (mappings == null) return;
//Not necessary anymore
//resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
}
public void Handle(EpisodeImportedEvent message)
{
//BroadcastResourceChange(ModelAction.Updated, message.ImportedEpisode.MovieId);
}
public void Handle(EpisodeFileDeletedEvent message)
{
if (message.Reason == DeleteMediaFileReason.Upgrade) return;
//BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.MovieId);
}
public void Handle(MovieUpdatedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
public void Handle(MovieEditedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
public void Handle(MovieDeletedEvent message)
{
BroadcastResourceChange(ModelAction.Deleted, message.Movie.ToResource());
}
public void Handle(MovieRenamedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
public void Handle(MediaCoversUpdatedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Movie.Id);
}
}
}

View File

@@ -1,236 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv;
using NzbDrone.Api.Series;
namespace NzbDrone.Api.Movie
{
public class MovieResource : RestResource
{
public MovieResource()
{
Monitored = true;
}
//Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately
//View Only
public string Title { get; set; }
public List<AlternateTitleResource> AlternateTitles { get; set; }
public string SortTitle { get; set; }
public long? SizeOnDisk { get; set; }
public MovieStatusType Status { get; set; }
public string Overview { get; set; }
public DateTime? InCinemas { get; set; }
public DateTime? PhysicalRelease { get; set; }
public List<MediaCover> Images { get; set; }
public string Website { get; set; }
public bool Downloaded { get; set; }
public string RemotePoster { get; set; }
public int Year { get; set; }
public bool HasFile { get; set; }
public string YouTubeTrailerId { get; set; }
public string Studio { get; set; }
//View & Edit
public string Path { get; set; }
public int ProfileId { get; set; }
//Editing Only
public bool Monitored { get; set; }
public MovieStatusType MinimumAvailability { get; set; }
public bool IsAvailable { get; set; }
public string FolderName { get; set; }
public int Runtime { get; set; }
public DateTime? LastInfoSync { get; set; }
public string CleanTitle { get; set; }
public string ImdbId { get; set; }
public int TmdbId { get; set; }
public string TitleSlug { get; set; }
public string RootFolderPath { get; set; }
public string Certification { get; set; }
public List<string> Genres { get; set; }
public HashSet<int> Tags { get; set; }
public DateTime Added { get; set; }
public AddMovieOptions AddOptions { get; set; }
public Ratings Ratings { get; set; }
public List<string> AlternativeTitles { get; set; }
public MovieFileResource MovieFile { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
//Used to support legacy consumers
public int QualityProfileId
{
get
{
return ProfileId;
}
set
{
if (value > 0 && ProfileId == 0)
{
ProfileId = value;
}
}
}
}
public static class MovieResourceMapper
{
public static MovieResource ToResource(this Core.Tv.Movie model)
{
if (model == null) return null;
long size = 0;
bool downloaded = false;
MovieFileResource movieFile = null;
if(model.MovieFile != null)
{
model.MovieFile.LazyLoad();
}
if (model.MovieFile != null && model.MovieFile.IsLoaded && model.MovieFile.Value != null)
{
size = model.MovieFile.Value.Size;
downloaded = true;
movieFile = model.MovieFile.Value.ToResource();
}
return new MovieResource
{
Id = model.Id,
TmdbId = model.TmdbId,
Title = model.Title,
//AlternateTitles
SortTitle = model.SortTitle,
InCinemas = model.InCinemas,
PhysicalRelease = model.PhysicalRelease,
HasFile = model.HasFile,
Downloaded = downloaded,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
//SizeOnDisk
Status = model.Status,
Overview = model.Overview,
//NextAiring
//PreviousAiring
Images = model.Images,
Year = model.Year,
Path = model.Path,
ProfileId = model.ProfileId,
Monitored = model.Monitored,
MinimumAvailability = model.MinimumAvailability,
IsAvailable = model.IsAvailable(),
FolderName = model.FolderName(),
SizeOnDisk = size,
Runtime = model.Runtime,
LastInfoSync = model.LastInfoSync,
CleanTitle = model.CleanTitle,
ImdbId = model.ImdbId,
TitleSlug = model.TitleSlug,
RootFolderPath = model.RootFolderPath,
Certification = model.Certification,
Website = model.Website,
Genres = model.Genres,
Tags = model.Tags,
Added = model.Added,
AddOptions = model.AddOptions,
AlternativeTitles = model.AlternativeTitles,
Ratings = model.Ratings,
MovieFile = movieFile,
YouTubeTrailerId = model.YouTubeTrailerId,
Studio = model.Studio
};
}
public static Core.Tv.Movie ToModel(this MovieResource resource)
{
if (resource == null) return null;
return new Core.Tv.Movie
{
Id = resource.Id,
TmdbId = resource.TmdbId,
Title = resource.Title,
//AlternateTitles
SortTitle = resource.SortTitle,
InCinemas = resource.InCinemas,
PhysicalRelease = resource.PhysicalRelease,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
//SizeOnDisk
Overview = resource.Overview,
//NextAiring
//PreviousAiring
Images = resource.Images,
Year = resource.Year,
Path = resource.Path,
ProfileId = resource.ProfileId,
Monitored = resource.Monitored,
MinimumAvailability = resource.MinimumAvailability,
Runtime = resource.Runtime,
LastInfoSync = resource.LastInfoSync,
CleanTitle = resource.CleanTitle,
ImdbId = resource.ImdbId,
TitleSlug = resource.TitleSlug,
RootFolderPath = resource.RootFolderPath,
Certification = resource.Certification,
Website = resource.Website,
Genres = resource.Genres,
Tags = resource.Tags,
Added = resource.Added,
AddOptions = resource.AddOptions,
AlternativeTitles = resource.AlternativeTitles,
Ratings = resource.Ratings,
YouTubeTrailerId = resource.YouTubeTrailerId,
Studio = resource.Studio
};
}
public static Core.Tv.Movie ToModel(this MovieResource resource, Core.Tv.Movie movie)
{
movie.ImdbId = resource.ImdbId;
movie.TmdbId = resource.TmdbId;
movie.Path = resource.Path;
movie.ProfileId = resource.ProfileId;
movie.Monitored = resource.Monitored;
movie.MinimumAvailability = resource.MinimumAvailability;
movie.RootFolderPath = resource.RootFolderPath;
movie.Tags = resource.Tags;
movie.AddOptions = resource.AddOptions;
return movie;
}
public static List<MovieResource> ToResource(this IEnumerable<Core.Tv.Movie> movies)
{
return movies.Select(ToResource).ToList();
}
}
}

View File

@@ -180,7 +180,7 @@ namespace NzbDrone.Api.Series
foreach (var season in resource.Seasons)
{
season.Statistics = SeasonStatisticsResourceMapper.ToResource(dictSeasonStats.GetValueOrDefault(season.SeasonNumber));
season.Statistics = dictSeasonStats.GetValueOrDefault(season.SeasonNumber).ToResource();
}
}
}
@@ -236,7 +236,7 @@ namespace NzbDrone.Api.Series
public void Handle(MediaCoversUpdatedEvent message)
{
//BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
}
}
}

View File

@@ -13,6 +13,8 @@ namespace NzbDrone.Api.System
{
private readonly IAppFolderInfo _appFolderInfo;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IPlatformInfo _platformInfo;
private readonly IOsInfo _osInfo;
private readonly IRouteCacheProvider _routeCacheProvider;
private readonly IConfigFileProvider _configFileProvider;
private readonly IMainDatabase _database;
@@ -20,14 +22,17 @@ namespace NzbDrone.Api.System
public SystemModule(IAppFolderInfo appFolderInfo,
IRuntimeInfo runtimeInfo,
IPlatformInfo platformInfo,
IOsInfo osInfo,
IRouteCacheProvider routeCacheProvider,
IConfigFileProvider configFileProvider,
IMainDatabase database,
ILifecycleService lifecycleService)
: base("system")
ILifecycleService lifecycleService) : base("system")
{
_appFolderInfo = appFolderInfo;
_runtimeInfo = runtimeInfo;
_platformInfo = platformInfo;
_osInfo = osInfo;
_routeCacheProvider = routeCacheProvider;
_configFileProvider = configFileProvider;
_database = database;
@@ -41,27 +46,29 @@ namespace NzbDrone.Api.System
private Response GetStatus()
{
return new
{
Version = BuildInfo.Version.ToString(),
BuildTime = BuildInfo.BuildDateTime,
IsDebug = BuildInfo.IsDebug,
IsProduction = RuntimeInfoBase.IsProduction,
IsAdmin = _runtimeInfo.IsAdmin,
IsUserInteractive = RuntimeInfoBase.IsUserInteractive,
StartupPath = _appFolderInfo.StartUpFolder,
AppData = _appFolderInfo.GetAppDataPath(),
OsVersion = OsInfo.Version.ToString(),
IsMonoRuntime = OsInfo.IsMonoRuntime,
IsMono = OsInfo.IsNotWindows,
IsLinux = OsInfo.IsLinux,
IsOsx = OsInfo.IsOsx,
IsWindows = OsInfo.IsWindows,
Branch = _configFileProvider.Branch,
Authentication = _configFileProvider.AuthenticationMethod,
SqliteVersion = _database.Version,
UrlBase = _configFileProvider.UrlBase,
RuntimeVersion = _runtimeInfo.RuntimeVersion
}.AsResponse();
{
Version = BuildInfo.Version.ToString(),
BuildTime = BuildInfo.BuildDateTime,
IsDebug = BuildInfo.IsDebug,
IsProduction = RuntimeInfo.IsProduction,
IsAdmin = _runtimeInfo.IsAdmin,
IsUserInteractive = RuntimeInfo.IsUserInteractive,
StartupPath = _appFolderInfo.StartUpFolder,
AppData = _appFolderInfo.GetAppDataPath(),
OsName = _osInfo.Name,
OsVersion = _osInfo.Version,
IsMonoRuntime = PlatformInfo.IsMono,
IsMono = PlatformInfo.IsMono,
IsLinux = OsInfo.IsLinux,
IsOsx = OsInfo.IsOsx,
IsWindows = OsInfo.IsWindows,
Branch = _configFileProvider.Branch,
Authentication = _configFileProvider.AuthenticationMethod,
SqliteVersion = _database.Version,
UrlBase = _configFileProvider.UrlBase,
RuntimeVersion = _platformInfo.Version,
RuntimeName = PlatformInfo.Platform
}.AsResponse();
}
private Response GetRoutes()

View File

@@ -7,7 +7,7 @@ namespace NzbDrone.Api.System.Tasks
{
public string Name { get; set; }
public string TaskName { get; set; }
public double Interval { get; set; }
public int Interval { get; set; }
public DateTime LastExecution { get; set; }
public DateTime NextExecution { get; set; }
}

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Api
/// </summary>
public static IEnumerable<Func<Assembly, bool>> DefaultAutoRegisterIgnoredAssemblies = new Func<Assembly, bool>[]
{
asm => !asm.FullName.StartsWith("Nancy.", StringComparison.InvariantCulture),
asm => !asm.FullName.StartsWith("Nancy.", StringComparison.InvariantCulture)
};
/// <summary>

View File

@@ -1,34 +0,0 @@
using FluentValidation.Validators;
namespace NzbDrone.Api.Validation
{
public class NetImportSyncIntervalValidator : PropertyValidator
{
public NetImportSyncIntervalValidator()
: base("Must be between 10 and 1440 or 0 to disable")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
if (context.PropertyValue == null)
{
return true;
}
var value = (int)context.PropertyValue;
if (value == 0)
{
return true;
}
if (value >= 10 && value <= 1440)
{
return true;
}
return false;
}
}
}

View File

@@ -5,7 +5,7 @@ namespace NzbDrone.Api.Validation
public class RssSyncIntervalValidator : PropertyValidator
{
public RssSyncIntervalValidator()
: base("Must be between 10 and 720 or 0 to disable")
: base("Must be between 10 and 120 or 0 to disable")
{
}
@@ -23,7 +23,7 @@ namespace NzbDrone.Api.Validation
return true;
}
if (value >= 10 && value <= 720)
if (value >= 10 && value <= 120)
{
return true;
}

View File

@@ -36,10 +36,5 @@ namespace NzbDrone.Api.Validation
{
return ruleBuilder.SetValidator(new RssSyncIntervalValidator());
}
public static IRuleBuilderOptions<T, int> IsValidNetImportSyncInterval<T>(this IRuleBuilder<T, int> ruleBuilder)
{
return ruleBuilder.SetValidator(new NetImportSyncIntervalValidator());
}
}
}

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