1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-05 13:21:25 -05:00

Compare commits

...

248 Commits

Author SHA1 Message Date
Leonardo Galli
f9049566c1 Fixed: No Physical Release Date causing exception when setting last write time.
Fixes #390
2018-02-06 16:51:19 +01:00
Leonardo Galli
0bc61bea38 Fixed: Movies not getting unmonitored when folder gets deleted.
Fixes #1191, Fixes #1590
2018-02-03 16:44:35 +01:00
Leonardo Galli
032fc68892 Added: Include total space with root folders
Closes #2468
2018-02-02 23:13:26 +01:00
Leonardo Galli
33cc228ac1 Fixed: Rare case of null quality causing issues with manual import.
Fixes #2227
2018-02-02 15:01:02 +01:00
Leonardo Galli
d5832a6a07 Added: Manual Import now adds year after movie title for filtering. This should help finding movies such as IT.
By searching e.g. It 2017, movies with short titles should be easily filterable now. Also displays more results (50 instead of 20)
2018-02-02 14:53:03 +01:00
Leonardo Galli
5f8aeeac17 Fixed: Manual Import not automatically choosing right movie.
Fixes #2458, Fixes #2061
Generally improved Manual Import UI
2018-02-02 14:51:18 +01:00
Leonardo Galli
54e57bf16a Merge remote-tracking branch 'origin/develop' into develop 2018-02-02 13:23:36 +01:00
Leonardo Galli
b1f76082b2 Added: Dynamic paths cleanup old folders now!
Old folder is now only left behind if extra files are also present in new dir and cannot be overwritten. Generally Dynamic Paths should be more stable now. Fixes #2048
2018-02-02 13:23:29 +01:00
Leonardo Galli
73fed04228 Fixed: Rare case of RequiredIndexerFlags failing with old Newznab indexers. 2018-02-01 16:00:55 +01:00
Leonardo Galli
ca3d5c184e Merge branch 'develop' of https://github.com/Radarr/Radarr into develop 2018-02-01 14:20:01 +01:00
Leonardo Galli
861962d06c Added: Option to require indexer flags per indexer. (e.g. only download freeleech torrents from a private tracker) (#2460) 2018-02-01 14:18:52 +01:00
Leonardo Galli
5057fcc40f Fixed: Folder name getting messed up when adding movies via a list.
Fixes #2465
2018-02-01 14:14:45 +01:00
Leonardo Galli
78e5fdf3bc Added: Files downloaded with different quality than grabbed will get rejected.
Fixes #1779, Fixes #2087, Fixes #1321
2018-01-31 20:09:04 +01:00
Leonardo Galli
aab14d02f9 Fixed: Error when adding an already excluded movie to the exclusion list.
Fixes #2462
2018-01-31 15:03:29 +01:00
Leonardo Galli
eb1c3c8b82 Fixed: Last commit still not compiling (whoops squared) 2018-01-30 18:33:30 +01:00
Leonardo Galli
4025af7895 Fixed: Last commit not compiling (whoops) 2018-01-30 18:31:07 +01:00
Leonardo Galli
95ca863697 Fixed: Clean Library being to agressive when lists are having failures.
Fixes #2455
2018-01-30 18:29:07 +01:00
Leonardo Galli
74e0db2829 @cosmetic Fixed all erroring tests. 2018-01-30 15:09:19 +01:00
Leonardo Galli
2459ddb6f4 Fixed: Error when nno quality was associated with a movie file.
Fixes #1991
2018-01-30 13:16:06 +01:00
Leonardo Galli
3e2e085b6b Fixed: Allowing in use Profiles to be Deleted.
Fixes #2030
2018-01-30 13:11:16 +01:00
Leonardo Galli
931cdacf66 Fixed: Error when Movie has no imdbid when searching Rargb
Fixes #2090
2018-01-30 12:59:45 +01:00
Leonardo Galli
18c622de40 Fixed: Rargb failing when imdbid is not found
Fixes #1845, Fixes #2319
2018-01-30 12:56:14 +01:00
Leonardo Galli
53e6fa7cf1 Fixed: {Original Filename} not allowed in Movie Filename
Fixes #1248
2018-01-30 12:42:06 +01:00
Qstick
4afd3f3bfe Fixed: Look for changes to package.json before using old build cache (#2445) 2018-01-26 08:54:59 +01:00
crhammock
da425b04b1 Updated: TMDbSettings.cs to allow pipe for or for genre ids (#2389) 2018-01-11 17:06:26 +01:00
Pieter Janssens
663ac972cd Fixed: HistoryDetailsLayoutTemplate.hbs (#2361) 2017-12-21 13:42:02 +01:00
Taloth Saldono
efbb587290 Fixed MediaCover endpoint. 2017-12-13 21:28:42 +01:00
Mark McDowall
72a12a73af Fixed: Don't handle content requests in IndexHtmlMapper 2017-12-13 21:28:21 +01:00
fhscholl
95bc93042c Added: Separate naming tags for AudioLanguage and SubtitleLanguage (#2261) (Fixes #2257) 2017-12-12 23:53:11 +01:00
Leonardo Galli
172cf4d06e Fixed: Movies parsed from lists with no year and only title getting added mutliple times. 2017-12-12 23:26:16 +01:00
Taloth Saldono
5ac0f28fff Fixed: Security Vulnerabilities allowing authentication to be bypassed (discovered by Kyle Neideck) 2017-12-12 23:15:46 +01:00
Leonardo Galli
948af901da Added: Include APFS disks in disk space calculation. 2017-12-12 22:46:00 +01:00
Leonardo Galli
f36716135b Added: Upgrade MediaInfo to 17.10 (Windows/macOS) 2017-12-12 22:44:14 +01:00
kriegalex
b70016d082 Added: Support for VF2 french tag. (#2291) (Fixes #2290) 2017-12-12 22:28:36 +01:00
grokdesigns
6a1b099117 Added: Customize Slack Channel (#2308) (Fixes #2298) 2017-12-04 09:07:42 +01:00
Leonardo Galli
ffb098357d Fixed: Movie Editor Path screwed up. Might also fix some other movie editor issues. (Fixes #2170) 2017-11-19 15:11:53 +01:00
Leonardo Galli
1a22486aba Fixed: Tags disappearing (Fixes #2204) 2017-11-19 14:57:15 +01:00
Fish2
72631eab8f Fixed: moment.js deprecated zone and add functions (Fixes #2232) (Fixes #2231) (#2264) 2017-11-16 20:20:41 +01:00
Mike
e4a3e63c44 Fixed: CPU locking at a 100% in certain instances. (#2258) (Fixes #2218) 2017-11-12 12:25:46 +01:00
Fish2
5dc2df3d49 Revert "Fixed: moment.js deprecated zone and Added: and lossless compression of images (#2232) (Fixes #2231)"
This reverts commit 32b1f75eb3.
2017-11-10 17:11:42 +01:00
fhscholl
01f0c6d85f Added: SceneName to MovieFile API output (#2250) (Fixes #2245) 2017-11-10 16:13:14 +01:00
fhscholl
c7c423b13d Added: Functionality to XBMC and Plex to update indivdual titles. Also: Notification Cleanup (#2240) 2017-11-10 16:11:09 +01:00
Fish2
32b1f75eb3 Fixed: moment.js deprecated zone and Added: and lossless compression of images (#2232) (Fixes #2231) 2017-11-10 16:08:02 +01:00
adnanklink
29909db604 Added: FolderPath to the Movie Webhook (#2230) 2017-11-10 16:06:45 +01:00
Mike
ec3f094d12 Fixes #2218. (#2254)
* Fixed: Raise ApplicationStartupEvent after Owin is running.

* Actually inject the container.
2017-11-08 19:39:50 +01:00
adnanklink
cb857934c4 Added: Download_Id to On Download/On Upgrade (#2229) 2017-10-29 19:19:30 +01:00
Leonardo Galli
d0174c7b7b Merge remote-tracking branch 'origin/develop' into develop 2017-10-29 12:24:41 +01:00
Leonardo Galli
9d19c4ec21 Fixed: Manual Import. Fixes #2160 2017-10-29 12:24:35 +01:00
fhscholl
0a030386f2 Added: Movie_Quality to onGrab (#2221) (Fixes #1833) 2017-10-28 17:19:49 +02:00
fhscholl
5e121c78e1 Updated: Webhook Improvements (#2220) (Fixes #1751) 2017-10-28 17:18:52 +02:00
James White
b521ffb588 Added: Message about adblockers preventing the log table from loading (#2213) (Fixes #2209) 2017-10-23 21:50:03 +02:00
James White
386a434aeb Changed: Sabnzbd Update test cases and rename to MovieCategory (#2212) 2017-10-23 21:49:02 +02:00
James White
5674d8ad60 Changed: Nzbget Rename TvCategory references to MovieCategory (#2211) 2017-10-23 21:47:49 +02:00
Oliver Rivett-Carnac
b313dd1845 Minor error message tweak (#1778)
* Added: some tips to how to build. Gave some info to Windows developers.

* Fixed: Alignment of validation errors in labels

* Fixed: error message mentioning 'series'
2017-10-22 20:58:25 -04:00
James White
dffa50a82f uTorrent initial state feature (#2192)
* New: Initial state for torrents added to UTorrent

Closes #409

(cherry picked from commit 19a4d3536b)

* Change default port

* Rename TvCategory to MovieCategory
2017-10-22 20:51:07 -04:00
James White
5337f79281 Change default port of qBittorrent download client config (#2187) 2017-10-22 20:49:54 -04:00
fhscholl
8861c8d8a4 Add IsUpgrade and related deleted file paths for CustomScript (#2205)
* Add IsUpgrade flag and deleted file paths for updates

* use OldMovieFiles instead of OldFiles
2017-10-22 20:49:37 -04:00
James White
4574ff5f6d Fixed: typo on margin-bottom (#2182) 2017-10-15 16:11:27 +02:00
James White
dd53e51468 @cosmetic Fix jshint warnings on MoviesCollection.js (#2180) 2017-10-15 13:37:19 +02:00
James White
7ae2d455c3 Fixed: Remove unit on zero values (#2178) 2017-10-15 13:29:32 +02:00
James White
e2e6630b69 Added: Initial state for torrents added to qBittorrent (#2176) 2017-10-15 12:35:53 +02:00
James White
ed744b5702 Fixed: Jackett apikey cleaned from log again. (#2177) 2017-10-15 12:35:04 +02:00
Leonardo Galli
5ffa27ec29 @cosmetic changed title 2017-10-14 12:05:17 +02:00
Leonardo Galli
53bfe61eb6 @cosmetic Added status images for websites and update api. 2017-10-14 12:04:22 +02:00
Leonardo Galli
a4a8e4547f Merge remote-tracking branch 'origin/develop' into develop 2017-10-11 23:09:36 +02:00
Leonardo Galli
e2bda29737 Fixed: Manual Movie Page Filtering. 2017-10-11 23:09:29 +02:00
James White
ab117082ed @cosmetic Stop commented out code appearing in HTML source (#2158) 2017-10-11 22:55:33 +02:00
Leonardo Galli
c708c3f5a1 Merge remote-tracking branch 'origin/develop' into develop 2017-10-11 22:54:51 +02:00
Leonardo Galli
a98494ab63 Fixed: MediaInfo not getting read when quality isn't Bluray, Web-dl or HDTV. Fixes #1465. Fixes #1572. 2017-10-11 22:54:45 +02:00
James White
779a722175 Changed: Adjust ambiguous date options (#2165)
(cherry picked from commit 00c3074216)
2017-10-11 22:45:15 +02:00
James White
805927205c @cosmetic Simplify ical ProductId code since adding properties (#2164) 2017-10-11 21:11:16 +02:00
James White
1d8eec42ef Added: a default name for Radarr.ics (#2163) 2017-10-11 19:19:57 +02:00
Leonardo Galli
a951ad811d @cosmetic Updated changelog. 2017-10-09 21:51:21 +02:00
James White
27c58f6151 Fixed: Alignment and buttons position of Trakt Auth (#2153) 2017-10-09 21:39:14 +02:00
Leonardo Galli
a5dd426dd7 Fixed: SUBBED in release name not recognized as hardcoded subs. Fixes #1520 2017-10-07 23:54:24 +02:00
Leonardo Galli
c30a681aea Fixed: 1080i not correctly recognized as 1080p. Fixes #1622 2017-10-07 23:47:22 +02:00
Leonardo Galli
4d712d7760 Fixed: Releases with UHD not getting correct resolution label. Fixes #2134 2017-10-07 20:24:50 +02:00
Leonardo Galli
63645c81bb Fixed: WebDL gets marked as Remux. Fixes #1954 2017-10-07 20:21:59 +02:00
Leonardo Galli
dc55eba74f Merge remote-tracking branch 'origin/develop' into develop 2017-10-07 20:20:47 +02:00
Leonardo Galli
b6be297093 Fixed: Parsing of TSRip and HDTSRip. Fixes #1998 2017-10-07 20:16:21 +02:00
Leonardo Galli
5ff9dc3500 Added: Option to omit year from indexer searches when searching by title. Also added option to force a movie search by title instead of imdb id. Fixes #1912 2017-10-07 20:09:22 +02:00
Wyall
4789f80df2 Added new codec HEVC with ID=5 for HDBits (#2146)
According to LSL1337 on Discord there's a new codec option HEVC with ID=5
2017-10-07 19:57:09 +02:00
Leonardo Galli
e77d9ce848 Added: Last round of optimisation. Large libraries should load around 2x faster again compared to the last version. 2017-10-07 18:16:15 +02:00
Leonardo Galli
a9b244bf75 Added: Improved load times of very large libraries again (around x5) 2017-10-05 23:31:12 +02:00
Leonardo Galli
628c044c46 Added: Movie files are now eager loaded. This should speed up the loading process a lot as well as RSS Sync and other tasks. It should also prevent some other bugs. 2017-10-01 18:41:19 +02:00
Leonardo Galli
ecd25dddf1 Merge remote-tracking branch 'origin/develop' into develop 2017-09-24 16:17:52 +02:00
Leonardo Galli
25b0a52ba6 Fixed: Alternative Titles appearing multiple times. Duplicate alt titles will be deleted. Fixes #2040 2017-09-24 16:17:43 +02:00
James White
321ba98e49 Fixed: unclosed <span> tag on BulkImportView (#2110) 2017-09-24 13:19:39 +02:00
James White
9178a0aa1b @cosmetic Convert backticks (#2112) 2017-09-24 13:16:05 +02:00
James White
6942fb892d Fixed: Change to correct provider of search results (#2113) 2017-09-24 13:15:35 +02:00
James White
f64d349119 Fixed: Icon not being hidden on Discover New Movies button in X-Small breakpoint (#2114) 2017-09-24 13:14:44 +02:00
James White
926dbdf2cd Fixed: Font folder case fix (#2066) 2017-09-21 22:37:10 +02:00
Adam Dangoor
645a3dca64 Fixed: Add space in confirmation message (#2101) 2017-09-20 07:55:44 +02:00
Leonardo Galli
2b2a1265ad Create LICENSE 2017-09-10 16:10:48 +02:00
Leonardo Galli
e7c9217dc0 Merge remote-tracking branch 'origin/develop' into develop 2017-09-10 15:58:47 +02:00
Leonardo Galli
8caf648a0b Fixed: Alt titles with less than 4 votes being used. 2017-09-10 15:58:31 +02:00
Leonardo Galli
349be2c454 Fixed: Cleanup of unused alt titles. 2017-09-10 15:56:45 +02:00
James White
ba0c5bc5f4 Fixed: Scripts should be included before closing body tag (#1995) 2017-09-10 15:55:36 +02:00
James White
1c1723b4f7 Fixed: Allow toolbar buttons to be full width on x-small and small breakpoints (#1972) 2017-09-10 15:55:03 +02:00
James White
c4957fffee Added: WOFF2 fonts for better performance in supported browsers (#1994) 2017-09-10 15:54:39 +02:00
James White
e6fee32cf2 Changed: Tweak NavbarLayoutTemplate.hbs (#1996) 2017-09-10 15:54:16 +02:00
Leonardo Galli
fc805e5078 Fixed: Refresh movie failing. 2017-08-27 18:55:55 +02:00
Leonardo Galli
ba531fff4d Added: Ability to force download movies that could not be mapped correctly. This also shares these mappings with other users, so everyone can profit :)
(This is just for the automatic changelog, hacky I know)
2017-08-27 18:12:09 +02:00
Leonardo Galli
1d7ce68431 Fixed: Refresh movie failing for most movies. (Fixes #2007)
Fixed: Invisible download button if no release name was found.
2017-08-27 18:05:28 +02:00
Leonardo Galli
09d51dca0f Fixed: A few issues with the new alternative titles feature. (#2008) (Fixes #1919, #1927 and #1917)
Added: Ability to force download movies that could not be mapped correctly. This also shares these mappings with other users, so everyone can profit :)
2017-08-27 16:42:11 +02:00
James White
efe49ef3c4 @cosmetic Make file name match naming format (#1997) 2017-08-25 08:37:24 +02:00
Leonardo Galli
a5823bb15f Fixed: A lot of small ui errors (e.g. More not showing) (Revert of #1959) 2017-08-24 07:57:31 +02:00
James White
38af8edd59 Fixed: Adjust Sonarr references to Radarr (#1977) 2017-08-21 21:48:45 +02:00
Leonardo Galli
685c5daf36 Fixed: Rename movie not working (#1970) (Fixes #1908) 2017-08-20 22:12:02 +02:00
Leonardo Galli
4d5a5ed2c1 Merge remote-tracking branch 'origin/develop' into develop 2017-08-20 20:13:48 +02:00
Leonardo Galli
d44de777c1 Fixed: Error with CP Import when no info is present. Fixes #1792 2017-08-20 20:13:42 +02:00
James White
dc2740aeb7 Added: Display breakpoint name in browser window in debug mode (#1968) 2017-08-20 20:00:37 +02:00
Leonardo Galli
fb53fc68a9 Added: Ability to delete multiple movies at once via the movie editor. 2017-08-20 18:58:29 +02:00
Tom
8de87bb516 Fixed: Movie files & folders will actually get deleted now (#1966) (Fixes #694) 2017-08-20 14:40:02 +02:00
James White
0c8e264668 Fixed: Bulk UI cleanup, fixes and consistency improvements (#1959) 2017-08-20 14:38:24 +02:00
MangaValk
4d8a270170 Fixed: Parser error when using (year) name folder (#1956) (Fixes #1951) 2017-08-19 00:24:41 +02:00
hotio
f184fc2827 @cosmetic Indicate proper release types for docker image (#1953) 2017-08-17 19:24:39 +02:00
hotio
4e48e6ea21 @cosmetic Update appveyor builds url to exclude pull requests (#1946) 2017-08-15 23:23:38 +02:00
Leonardo Galli
b1e75ffc57 Merge remote-tracking branch 'origin/develop' into develop 2017-08-15 23:22:43 +02:00
Leonardo Galli
285ffb19d8 Fixed: Non-Freeleech torrents showing as freeleech for AHD. 2017-08-15 23:22:00 +02:00
hotio
aea7a3f48f @cosmetic Update docker nightly image reference (#1945) 2017-08-15 23:07:34 +02:00
James White
edbf1cb4e4 Fixed: Missing icon preventing detailed explanation validation errors explanations from appearing. (#1944) 2017-08-15 22:54:59 +02:00
Leonardo Galli
2154c48304 @cosmetic Removed Tests from AppVeyor 2017-08-15 20:23:02 +02:00
James White
7a95f040c9 Added: Deprecation warning about Drone Factory to front end (#1938) 2017-08-15 20:22:17 +02:00
James White
cc1966230a Added: Package-lock.json for npm 5 (#1939) 2017-08-15 20:21:59 +02:00
James White
e97fe7b3a7 Fixed: Mask-icon and other resources when UrlBase is in use (#1933) 2017-08-13 22:56:56 +02:00
James White
6500edbd14 Fixed: Slack/Mattermost notifications improvements from Sonarr (#1930) 2017-08-13 19:42:00 +02:00
James White
e155585198 Fixed: fontawesome path (Icons disappearing) (#1929) 2017-08-13 14:18:54 +02:00
James White
d9da32173f Fixed: Charset and meta in index.html and login.html (#1926) 2017-08-13 12:57:10 +02:00
Rotem
9db46ba154 Fixed: Removed hebrew ISO, since english movies are still in english. (#1922) 2017-08-13 12:55:25 +02:00
James White
eff6e33a0b Fixed: Adjust column sizes relative to size of dropdown values (#1923) 2017-08-13 12:54:44 +02:00
James White
724097d276 Updated FontAwesome to 4.7.0 (#1928) 2017-08-13 12:54:16 +02:00
James White
7a06ead806 Fixed: Additional jshint warnings (#1921) 2017-08-12 17:11:34 +02:00
James White
d773da60e8 Fixed: Minor issues on MoreInfoViewTemplate.hbs (#1916) 2017-08-12 15:16:31 +02:00
James White
1f7b03d321 Fixed: gulp jshint warnings (#1873) 2017-08-12 15:16:12 +02:00
James White
a07ef20410 Fixed: Replace GitHub wiki references to Radarr's wiki URL (#1914) 2017-08-12 15:15:23 +02:00
Rotem
7c4c6ccd5c Added: Hebrew language (#1909) 2017-08-12 00:48:57 +02:00
James White
c754edc4b8 Fixed: Hanging form-group div (#1911) 2017-08-12 00:29:31 +02:00
Mike
7f3ab36c4f New: Run tests through powershell. (#1903) 2017-08-10 20:11:12 +02:00
Leonardo Galli
17387c8b50 Fixed: Migration failing and thus making Radarr unable to start. 2017-08-10 18:51:05 +02:00
Leonardo Galli
0d40ed7ec0 Added: Alternative Titles are now also pulled from mappings.radarr.video.
Added: A secondary year will also be pulled from mappings.radarr.video.
Added: An option to force download a movie with wrong year / title. Radarr then adds the year / title to mappings.radarr.video.
2017-08-09 22:18:04 +02:00
Leonardo Galli
cfcb66fba1 Changed: Alternative Titles were reworked greatly. This should speed up RSS Sync massively, especially for large libraries (up to 4x). 2017-08-09 22:14:01 +02:00
James White
8927e7c2c6 Fixed: Task name of PreDB Sync task (#1875) 2017-08-06 17:47:23 +02:00
Qstick
4e9a931537 Fixed: Check that Quality Profile is not in use before deleting it. 2017-08-06 12:10:17 +02:00
James White
17feedaf53 Fixed: Category not setting with qBitTorrent 3.3.14 and other api errors. (upstream from Sonarr) 2017-08-06 12:09:16 +02:00
Leonardo Galli
b06108fb45 Fixed: Older movies (released more than 30 days ago) are now not refreshed as often anymore (every 30 days) 2017-07-28 16:59:06 +02:00
Leonardo Galli
67dd498576 Fixed: (Hopefully) Bug where movie file was not correctly linked to movie. 2017-07-28 16:57:26 +02:00
Leonardo Galli
3fb356ddb6 Fixed: No API Key required with SignalR connections. 2017-07-26 23:24:28 +02:00
Leonardo Galli
605b8f9645 Fixed: Guard agains null reference exception with newznab capabilities. 2017-07-26 23:23:36 +02:00
Marc Runkel
668ef336fb Fixed: Update Info.plist to avoid conflict with Sonarr (#1783) 2017-07-16 14:09:03 +01:00
Richard Schwab
b82f2376a7 Fixed: Relax SingleInstancePolicy when using a custom data directory Fixes #1765 (#1782) 2017-07-16 14:08:16 +01:00
Leonardo Galli
964c18b236 Fixed: Lists are fetched much more efficiently. (Up to 40x loading time improvement with large lists!) 2017-07-08 16:13:28 +02:00
Taloth Saldono
fb4f510909 Revert "Fixed: Support for Mono 5.x with the newer BoringTLS provider."
This reverts commit 5b722a3a48.
2017-07-06 21:45:37 +02:00
Taloth Saldono
5b722a3a48 Fixed: Support for Mono 5.x with the newer BoringTLS provider. 2017-07-06 21:43:34 +02:00
Sandro Stikić
0892f20298 Fixed: Old Plex ValidationFailure message (#1770) 2017-07-06 18:48:46 +02:00
Leonardo Galli
ac5732536d Fixed: BDRemux not recognized as such and BDRips without resolution recognized as DVD. Fixes #1755 2017-07-01 14:01:38 +02:00
Leonardo Galli
1f4c2ad946 Fixed: A as part of an acronym being removed from clean title. Fixes #1747 2017-07-01 11:01:48 +02:00
Leonardo Galli
7712aa62da Fixed: Folder in List settings appearing blank in some browsers. Fixes #1711 2017-06-27 12:53:50 +02:00
Leonardo Galli
58b9c9d3d1 Fixed: Minimum Seeders not saving for Torznab indexer. Fixes #1736 2017-06-27 12:36:24 +02:00
Leonardo Galli
b2115e2066 Removed most of changelog. Generate changelog using gitchangelog v0.2.0.18..HEAD. @cosmetic 2017-06-20 14:29:32 +02:00
Leonardo Galli
4e4873271b Added Changelog, just for fun :D @cosmetic 2017-06-20 14:21:19 +02:00
Leonardo Galli
f2e5d9e996 Updated: Radarr API url now points to new v2 version. 2017-06-20 10:23:26 +02:00
Leonardo Galli
bae3a48aa1 Changed Name of Radarr Lists 2017-06-19 15:22:03 +02:00
Leonardo Galli
6d033c57f4 Added: More detailed descriptions why a movie was not able to be mapped. (#1696)
Added: Option to make mapping more lenient. This should practically allow all movies to be correctly mapped. Though it also opens the path for movies being wrongly mapped! (So it is a toggable option)

Added: Improved edition parsing. Now almost all releases should have the correct edition, even ones with no year, etc.
2017-06-18 23:12:14 +02:00
Leonardo Galli
d6cf53e12c Added: Options to make parsing more lenient. (Adds support for some german and french releasegroups) (#1692)
Fixes #1676. Fixes #1632.
2017-06-17 15:02:58 +02:00
Leonardo Galli
5238b78813 Merge remote-tracking branch 'origin/develop' into develop 2017-06-13 16:10:17 +02:00
Leonardo Galli
705b233819 Fix migration.
Fixes #1678
2017-06-13 16:09:12 +02:00
Mitchell Cash
295536ae30 Updated: Bootstrap Tags Input (#1674) 2017-06-13 13:15:43 +02:00
Leonardo Galli
42c980c905 Merge remote-tracking branch 'origin/develop' into develop 2017-06-13 13:09:09 +02:00
Leonardo Galli
0a71aac56c Fixed: Urls missing from multiple indexers after latest nightly update. 2017-06-13 13:09:02 +02:00
Mitchell Cash
c312ffd7db Fixed: Redirect calls missing URL Base (#1668) 2017-06-13 08:42:49 +02:00
Mitchell Cash
5c5f06a92c Fixed: Twitter oAuth callback URL (#1669) 2017-06-13 08:42:07 +02:00
Mitchell Cash
3eab8248e6 Fixed: Error when processing manual import decisions (#1670) 2017-06-13 08:40:51 +02:00
Mitchell Cash
c33d9727a0 Added: Include css files in minification (#1672) 2017-06-13 08:39:42 +02:00
Mitchell Cash
ca6784f7b5 Added: Upgrade to Bootstrap 3.3.7 (#1673) 2017-06-13 08:38:39 +02:00
Leonardo Galli
ca00d0d6cc Create README.md 2017-06-12 19:17:56 +02:00
Leonardo Galli
756fc7556c Add license 2017-06-12 19:11:11 +02:00
Leonardo Galli
9f4ce50dd6 Added: Allow minimum seeders to be set on a per indexer basis. Pulled from Sonarr Upstream (#1624) 2017-06-12 14:47:05 +02:00
Leonardo Galli
a460e89a8d Merge remote-tracking branch 'origin/develop' into develop 2017-06-12 14:10:18 +02:00
Leonardo Galli
edda8786ad Minimum availability is now working similarely to profile when adding a movie. 2017-06-12 14:10:07 +02:00
Mitchell Cash
b1c5dd8167 Changed: Remove redundant IE meta tag as we use http header instead (#1655) 2017-06-11 09:32:12 +02:00
Mitchell Cash
a620c4b5d8 Changed: Use cleancss for minification (#1654) 2017-06-11 09:31:27 +02:00
Mitchell Cash
28b523b504 Fixed: Follow 301 redirects when fetching torrents (#1653)
Closes #1564
2017-06-11 09:30:51 +02:00
Mitchell Cash
7af88037bb Fixed: Ensure an API Key is set when starting Radarr (#1652) 2017-06-11 09:30:00 +02:00
Leonardo Galli
43446ee3d0 Fixed: Forgot to include some js files in the last commit 2017-06-07 13:37:20 +02:00
Leonardo Galli
accf8a9efa Added: Ability to see TMDB and lists going through the Radarr API on the discovery page.
Added: More lists (specifically presets for IMDB Top 250 and IMDB Popular)
Added: Ability to set Radarr API endpoint as list.
2017-06-06 22:40:44 +02:00
Leonardo Galli
b70ed720c5 Fix error when we get invalid datetime from our api. 2017-06-06 20:03:52 +02:00
Leonardo Galli
cff4578c66 Merge remote-tracking branch 'origin/develop' into develop 2017-06-06 19:51:00 +02:00
Leonardo Galli
7bbebe53a3 Added: Custom Class for Radarr API requests. Also implements new error handling present on staging server. 2017-06-06 19:50:53 +02:00
Leonardo Galli
d81e3a79cf Added: Search 5 alternative titles as well. This should help with french as well as movies with very different titles. 2017-06-05 17:48:04 +02:00
Jason Costomiris
09c86013b0 Added: [Radarr] tag for Twitter Notifications (#1558) 2017-06-05 12:06:20 +02:00
Fish2
f1873a9684 lossless compression of images saved 92KB (#1620) 2017-06-04 13:11:52 +02:00
randellhodges
3d48da2111 Added HDBits Category, Codec, and Medium Filtering Capability (#1458)
* Added advanced configuration options to support filtering Categories, Codecs, and Medium to the HDBits indexer.

* Changes to use the existing tags with a controlled vocabulary.

* 1) Sorting select options by name
2) Moved the autocomplete tag code into taginput as requested

* removed commented out line

* require cleanups
2017-05-29 17:56:16 +02:00
Leonardo Galli
86634006e5 update radarr api url 2017-05-29 15:49:42 +02:00
Leonardo Galli
234827d5fd Mostly fixes UI glitches for list settings.
Fixes #679
2017-05-26 18:31:11 +02:00
Leonardo Galli
10bceaf370 Merge remote-tracking branch 'origin/develop' into develop 2017-05-26 11:12:14 +02:00
Leonardo Galli
b7f6ff7b2e Fixed PTP indexer being disabled if no results are found for a movie.
Fixes #1573
2017-05-26 11:12:07 +02:00
Sentir101
6767f602fb Refresh IsDuplicate in bulk import when the tmdbId changes (#1570) 2017-05-25 15:44:43 +02:00
flightlevel
e43e7d2b8d Encourage Torznab use with Jackett (#1559) 2017-05-23 17:30:59 +02:00
Leonardo Galli
811a4bf117 Fix basic naming settings.
Fixes #376
2017-05-21 18:10:46 +02:00
Leonardo Galli
9dee1d6fad Discovery of upcoming movies points to our server now.
Discovery results now show physical release date (if present).
All physical release dates now should show a note (if available) detailing what kind of release date it is (e.g. Netflix, DVD, Streaming, etc.)
2017-05-20 14:31:38 +02:00
Mike
390e4c3014 Most likely fixed #745 now 2017-05-18 01:08:13 +02:00
Mike
aace29e1e1 Chmod osx file as executable. (#1539) 2017-05-17 11:20:32 +02:00
tsubus
8fb257d5b7 Add IMDB URL to notifications (#1531) 2017-05-15 14:47:22 +02:00
Levi Wilcox
28e0f85e88 Fixed design calendar css bug (#1527)
Fixes #983
2017-05-15 09:40:00 +02:00
Luke Anderson
41d3f6d7ea Correct Program Name (#1524) 2017-05-14 12:19:20 +02:00
Luke Anderson
b19fbcbb71 Correct Program Name (#1523) 2017-05-14 12:19:10 +02:00
Leonardo Galli
5200758200 Osx updater now updates plist file to point to the correct executable binary. 2017-05-14 11:08:33 +02:00
Leonardo Galli
6210c5b8f8 Merge remote-tracking branch 'origin/develop' into develop 2017-05-14 11:03:28 +02:00
Leonardo Galli
6e31f7220c Fix osx updater failing. 2017-05-14 11:03:20 +02:00
Leonardo Galli
797a9acff5 Update TaskManager.cs 2017-05-13 21:22:55 +02:00
Leonardo Galli
b36053e1f4 Update LogEntries token again :) 2017-05-13 20:32:55 +02:00
Leonardo Galli
212bcebdaf Fixed: Using our own logentries token now.
Fixes #1517
2017-05-13 13:11:54 +02:00
Leonardo Galli
3c8162f1d6 Fix test. 2017-05-12 16:52:38 +02:00
Leonardo Galli
096d24ed91 Merge branch 'feature/better-mapping-info' into develop 2017-05-12 16:09:35 +02:00
Leonardo Galli
63e3361fb5 Movies with same name but different year being downloaded regardlessly is now fixed! 2017-05-12 16:09:23 +02:00
Leonardo Galli
51854ef73b Update TaskManager.cs 2017-05-11 23:05:12 +02:00
Levi Wilcox
a0486b54a6 Fixed design issue when deleting css bug (#1480) Fixes #1475 2017-05-11 22:05:34 +02:00
Leonardo Galli
7ed0db10cb 10 Movies are now shown on discover as well as search results.
Show more should also be more consistent now.
2017-05-09 22:28:15 +02:00
Leonardo Galli
e94591a290 Hotfix for when ignored movies would appear again after clicking on show more. 2017-05-09 21:28:22 +02:00
Leonardo Galli
fccd02a0ca Merge remote-tracking branch 'origin/develop' into develop 2017-05-09 20:44:43 +02:00
Leonardo Galli
b49f0e70ed Merge branch 'feature/better-import-exclusions' into develop 2017-05-09 20:44:17 +02:00
Leonardo Galli
fc1585e900 Completely overhauled how import exclusions work.
Currently new exclusions can only be added when adding new movies or deleting old ones. Not manually in the settings menu.
Movies can now be hidden in the new discover feature by using the new import exclusions!
2017-05-09 20:44:07 +02:00
Leonardo Galli
b36ac091fc Fix appveyor build 2017-05-09 19:49:30 +02:00
Leonardo Galli
ab28bfead2 Merge branch 'develop' into feature/better-import-exclusions 2017-05-09 16:55:19 +02:00
Leonardo Galli
3ab3fbfd57 Added ability to discover new movies based on upcoming blurays as well as popular movies (borrowed from steven lu :)) 2017-05-09 16:46:19 +02:00
Leonardo Galli
d133ee3143 Hopefully more logging to catch errors better. 2017-05-08 18:46:03 +02:00
Leonardo Galli
98b6932ffe Merge remote-tracking branch 'origin/develop' into develop 2017-05-08 18:07:38 +02:00
Leonardo Galli
58e81a916c Fixed error when language is present in title, but has dots instead of spaces. For example The.Danish.Girl.2015 2017-05-06 15:26:35 +02:00
PatrickGHanna
817f48448c Fix: A small bug fix for items loading as undefined in organize modal. Movie titles should now show up correctly. (#1424) 2017-05-06 12:31:41 +02:00
hotio
1eca179b4e Update Kodi icon, fixes #1464 (#1492) 2017-05-06 12:30:36 +02:00
Leonardo Galli
b05d505bce Fixed Final in titles parsing as an edition. 2017-05-02 22:15:03 +02:00
Leonardo Galli
ace426e69f Added initial migration. 2017-04-30 14:05:41 +02:00
Mitchell Cash
a57c9917cc Fixed: Radarr not importing torrents in Vuze if the torrent already finished seeding and was stopped (#1471) 2017-04-30 13:14:49 +02:00
Mitchell Cash
9e84b4a782 Fixed: Incorrect imports with Vuze when torrent contains a single file. (#1470) 2017-04-30 10:37:51 +02:00
Mitchell Cash
494ef16735 Fixed: Sonarr UI Authentication cookie should be placed on path (UrlBase) instead of domain alone. Fixes ##1451 2017-04-30 10:30:59 +02:00
Leonardo Galli
5a0f02007f Added trailer links to the discovery page. 2017-04-28 14:14:02 +02:00
Leonardo Galli
b1025e7229 Use Post for tmdbids request, to avoid too long URIs. 2017-04-28 13:14:00 +02:00
Leonardo Galli
446d661345 Added discovery tab based on tmdb recommendations based on your existing movies. (#1450)
Keep scroll position on more in search result view.
Added TMDB score to search results.
2017-04-28 11:04:30 +02:00
David Pooley
3eb351823e Tidy up layout of buttons on the Add Movies page for mobile/tablet (#1454) 2017-04-28 10:59:55 +02:00
morberg
835a7cffa1 Rename Sonarr to Radarr for OSX App 2017-04-26 18:44:57 +02:00
Leonardo Galli
e728330ce4 Minor text fixes. 2017-04-26 15:45:06 +02:00
Leonardo Galli
6f3118c142 Merge remote-tracking branch 'origin/develop' into develop 2017-04-26 15:17:49 +02:00
Leonardo Galli
b568072140 Change default page size to 250. Should help with safari timeouts. 2017-04-26 15:17:42 +02:00
Leonardo Galli
7db92c6bcf Enable automatic renaming, according to naming scheme, of movie folder after creation of the movie. (#1349)
Please test everything you can about this and report back if everything still works correctly.
2017-04-26 13:31:55 +02:00
Leonardo Galli
f1e8a9acfc Fix for error when clicking Rescan Drone Folder 2017-04-19 22:04:34 +02:00
Leonardo Galli
dae389ce64 Fix for error when trying to manually import. 2017-04-19 22:03:52 +02:00
Leonardo Galli
7c3d8c8ff9 Added multiple new editions such as FanEdit, Anniversary and 2in1. 2017-04-19 21:02:01 +02:00
662 changed files with 27621 additions and 4258 deletions

293
.gitchangelog.rc Normal file
View File

@@ -0,0 +1,293 @@
# -*- coding: utf-8; mode: python -*-
##
## Format
##
## ACTION: [AUDIENCE:] COMMIT_MSG [!TAG ...]
##
## Description
##
## ACTION is one of 'chg', 'fix', 'new'
##
## Is WHAT the change is about.
##
## 'chg' is for refactor, small improvement, cosmetic changes...
## 'fix' is for bug fixes
## 'new' is for new features, big improvement
##
## AUDIENCE is optional and one of 'dev', 'usr', 'pkg', 'test', 'doc'
##
## Is WHO is concerned by the change.
##
## 'dev' is for developpers (API changes, refactors...)
## 'usr' is for final users (UI changes)
## 'pkg' is for packagers (packaging changes)
## 'test' is for testers (test only related changes)
## 'doc' is for doc guys (doc only changes)
##
## COMMIT_MSG is ... well ... the commit message itself.
##
## TAGs are additionnal adjective as 'refactor' 'minor' 'cosmetic'
##
## They are preceded with a '!' or a '@' (prefer the former, as the
## latter is wrongly interpreted in github.) Commonly used tags are:
##
## 'refactor' is obviously for refactoring code only
## 'minor' is for a very meaningless change (a typo, adding a comment)
## 'cosmetic' is for cosmetic driven change (re-indentation, 80-col...)
## 'wip' is for partial functionality but complete subfunctionality.
##
## Example:
##
## new: usr: support of bazaar implemented
## chg: re-indentend some lines !cosmetic
## new: dev: updated code to be compatible with last version of killer lib.
## fix: pkg: updated year of licence coverage.
## new: test: added a bunch of test around user usability of feature X.
## fix: typo in spelling my name in comment. !minor
##
## Please note that multi-line commit message are supported, and only the
## first line will be considered as the "summary" of the commit message. So
## tags, and other rules only applies to the summary. The body of the commit
## message will be displayed in the changelog without reformatting.
##
## ``ignore_regexps`` is a line of regexps
##
## Any commit having its full commit message matching any regexp listed here
## will be ignored and won't be reported in the changelog.
##
ignore_regexps = [
r'@minor', r'!minor',
r'@cosmetic', r'!cosmetic',
r'@refactor', r'!refactor',
r'@wip', r'!wip',
r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[p|P]kg:',
r'^([cC]hg|[fF]ix|[nN]ew)\s*:\s*[d|D]ev:',
r'^(.{3,3}\s*:)?\s*[fF]irst commit.?\s*$',
r'^$', ## ignore commits with empty messages
]
## ``section_regexps`` is a list of 2-tuples associating a string label and a
## list of regexp
##
## Commit messages will be classified in sections thanks to this. Section
## titles are the label, and a commit is classified under this section if any
## of the regexps associated is matching.
##
## Please note that ``section_regexps`` will only classify commits and won't
## make any changes to the contents. So you'll probably want to go check
## ``subject_process`` (or ``body_process``) to do some changes to the subject,
## whenever you are tweaking this variable.
##
section_regexps = [
('**New features**', [
r'^[aA]dded?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
r'^[uU]pdated?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
r'^[cC]hanged?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
]),
('**Fixes**', [
r'^(?![mM]erge\s*)'
]
),
]
## ``body_process`` is a callable
##
## This callable will be given the original body and result will
## be used in the changelog.
##
## Available constructs are:
##
## - any python callable that take one txt argument and return txt argument.
##
## - ReSub(pattern, replacement): will apply regexp substitution.
##
## - Indent(chars=" "): will indent the text with the prefix
## Please remember that template engines gets also to modify the text and
## will usually indent themselves the text if needed.
##
## - Wrap(regexp=r"\n\n"): re-wrap text in separate paragraph to fill 80-Columns
##
## - noop: do nothing
##
## - ucfirst: ensure the first letter is uppercase.
## (usually used in the ``subject_process`` pipeline)
##
## - final_dot: ensure text finishes with a dot
## (usually used in the ``subject_process`` pipeline)
##
## - strip: remove any spaces before or after the content of the string
##
## - SetIfEmpty(msg="No commit message."): will set the text to
## whatever given ``msg`` if the current text is empty.
##
## Additionally, you can `pipe` the provided filters, for instance:
#body_process = Wrap(regexp=r'\n(?=\w+\s*:)') | Indent(chars=" ")
#body_process = Wrap(regexp=r'\n(?=\w+\s*:)')
#body_process = noop
body_process = ReSub(r'((^|\n)[A-Z]\w+(-\w+)*: .*(\n\s+.*)*)+$', r'') | strip
## ``subject_process`` is a callable
##
## This callable will be given the original subject and result will
## be used in the changelog.
##
## Available constructs are those listed in ``body_process`` doc.
subject_process = (strip |
ReSub(r'^([cC]hanged|[fF]ixed|[aA]dded|[uU]pdated)\s*:\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n@]*)(@[a-z]+\s+)*$', r'\4') |
SetIfEmpty("No commit message.") | ucfirst | final_dot)
## ``tag_filter_regexp`` is a regexp
##
## Tags that will be used for the changelog must match this regexp.
##
tag_filter_regexp = r'^v[0]+\.[2-9]+\.[0-9]+\.[0-9]+$'
## ``unreleased_version_label`` is a string or a callable that outputs a string
##
## This label will be used as the changelog Title of the last set of changes
## between last valid tag and HEAD if any.
unreleased_version_label = "(unreleased)"
## ``output_engine`` is a callable
##
## This will change the output format of the generated changelog file
##
## Available choices are:
##
## - rest_py
##
## Legacy pure python engine, outputs ReSTructured text.
## This is the default.
##
## - mustache(<template_name>)
##
## Template name could be any of the available templates in
## ``templates/mustache/*.tpl``.
## Requires python package ``pystache``.
## Examples:
## - mustache("markdown")
## - mustache("restructuredtext")
##
## - makotemplate(<template_name>)
##
## Template name could be any of the available templates in
## ``templates/mako/*.tpl``.
## Requires python package ``mako``.
## Examples:
## - makotemplate("restructuredtext")
##
#output_engine = rest_py
#output_engine = mustache("restructuredtext")
output_engine = mustache("changelog.tpl")
#output_engine = makotemplate("restructuredtext")
## ``include_merge`` is a boolean
##
## This option tells git-log whether to include merge commits in the log.
## The default is to include them.
include_merge = False
## ``log_encoding`` is a string identifier
##
## This option tells gitchangelog what encoding is outputed by ``git log``.
## The default is to be clever about it: it checks ``git config`` for
## ``i18n.logOutputEncoding``, and if not found will default to git's own
## default: ``utf-8``.
#log_encoding = 'utf-8'
## ``publish`` is a callable
##
## Sets what ``gitchangelog`` should do with the output generated by
## the output engine. ``publish`` is a callable taking one argument
## that is an interator on lines from the output engine.
##
## Some helper callable are provided:
##
## Available choices are:
##
## - stdout
##
## Outputs directly to standard output
## (This is the default)
##
## - FileInsertAtFirstRegexMatch(file, pattern, idx=lamda m: m.start())
##
## Creates a callable that will parse given file for the given
## regex pattern and will insert the output in the file.
## ``idx`` is a callable that receive the matching object and
## must return a integer index point where to insert the
## the output in the file. Default is to return the position of
## the start of the matched string.
##
## - FileRegexSubst(file, pattern, replace, flags)
##
## Apply a replace inplace in the given file. Your regex pattern must
## take care of everything and might be more complex. Check the README
## for a complete copy-pastable example.
##
# publish = FileInsertIntoFirstRegexMatch(
# "CHANGELOG.rst",
# r'/(?P<rev>[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n/',
# idx=lambda m: m.start(1)
# )
#publish = stdout
def write_to_file(content):
with open("CHANGELOG.md", "w+") as f:
for chunk in content:
f.write(chunk)
publish = write_to_file
## ``revs`` is a list of callable or a list of string
##
## callable will be called to resolve as strings and allow dynamical
## computation of these. The result will be used as revisions for
## gitchangelog (as if directly stated on the command line). This allows
## to filter exaclty which commits will be read by gitchangelog.
##
## To get a full documentation on the format of these strings, please
## refer to the ``git rev-list`` arguments. There are many examples.
##
## Using callables is especially useful, for instance, if you
## are using gitchangelog to generate incrementally your changelog.
##
## Some helpers are provided, you can use them::
##
## - FileFirstRegexMatch(file, pattern): will return a callable that will
## return the first string match for the given pattern in the given file.
## If you use named sub-patterns in your regex pattern, it'll output only
## the string matching the regex pattern named "rev".
##
## - Caret(rev): will return the rev prefixed by a "^", which is a
## way to remove the given revision and all its ancestor.
##
## Please note that if you provide a rev-list on the command line, it'll
## replace this value (which will then be ignored).
##
## If empty, then ``gitchangelog`` will act as it had to generate a full
## changelog.
##
## The default is to use all commits to make the changelog.
#revs = ["^1.0.3", ]
#revs = [
# Caret(
# FileFirstRegexMatch(
# "CHANGELOG.rst",
# r"(?P<rev>[0-9]+\.[0-9]+(\.[0-9]+)?)\s+\([0-9]+-[0-9]{2}-[0-9]{2}\)\n--+\n")),
# "HEAD"
#]
revs = []

3
.gitignore vendored
View File

@@ -150,3 +150,6 @@ Thumbs.db
# AppVeyor
/tools-cake/
/_artifacts/
# Cake
/tools/Addins/*

1
.idea/Sonarr.iml generated
View File

@@ -20,6 +20,5 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Sonarr node_modules" level="project" />
</component>
</module>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="ECMAScript 6" />
<excludedPredefinedLibrary name="Radarr/node_modules" />
</component>
</project>

View File

@@ -1,14 +0,0 @@
<component name="libraryTable">
<library name="Sonarr node_modules" type="javaScript">
<properties>
<option name="frameworkName" value="node_modules" />
<sourceFilesUrls>
<item url="file://$PROJECT_DIR$/node_modules" />
</sourceFilesUrls>
</properties>
<CLASSES>
<root url="file://$PROJECT_DIR$/node_modules" />
</CLASSES>
<SOURCES />
</library>
</component>

7670
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

674
LICENSE Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 B

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 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.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -21,10 +21,10 @@ The project was inspired by other Usenet/BitTorrent movie downloaders such as Co
## Downloads
[![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases)
[![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/build/artifacts)
[![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/branch/develop/artifacts)
[![Docker 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 nightly](https://img.shields.io/badge/docker-release/nightly-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/hotio/suitarr)
[![Docker armhf](https://img.shields.io/badge/docker-armhf-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr)
[![Docker aarch64](https://img.shields.io/badge/docker-aarch64-blue.svg?colorB=1488C6&maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
@@ -50,7 +50,12 @@ The project was inspired by other Usenet/BitTorrent movie downloaders such as Co
| 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.**
### [Site and API Status](https://status.radarr.video)
| API | Updates | Sites |
|-------|:----:|:----:|
| [![API V2](http://status.radarr.video/component/1/shield?style=flat-square)](https://api.radarr.video/v2/) | [![Update Server](http://status.radarr.video/component/4/shield?style=flat-square)](https://radarr.aeonlucid.com) | [![Radarr Mappings](http://status.radarr.video/component/6/shield?style=flat-square)](https://mappings.radarr.video/)
| [![API Staging](http://status.radarr.video/component/2/shield?style=flat-square)](https://staging.api.radarr.video/) | [![Github Updates](http://status.radarr.video/component/5/shield?style=flat-square)](https://api.github.com/v3/) | [![Main Site](http://status.radarr.video/component/7/shield?style=flat-square)](https://radarr.video/)
Radarr is currently undergoing rapid development and pull requests are actively added into the repository.
@@ -71,7 +76,8 @@ Radarr is currently undergoing rapid development and pull requests are actively
* 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))
* New TorrentPotato Indexer
* Torznab Indexer now supports Movies (Works well with [Jackett](https://github.com/Jackett/Jackett))
* Scanning PreDB to know when a new release is available
* 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)
@@ -109,14 +115,19 @@ Radarr is currently undergoing rapid development and pull requests are actively
> **Notice**
> Gulp must be running at all times while you are working with Radarr client source files.
### Build
* To build run `sh build.sh`
**Note:** Windows users must have bash available to do this. [cmder](http://cmder.net/) which is a console emulator for windows has bash as part of it's default installation.
### Development
* Open `NzbDrone.sln` in Visual Studio or run the build.sh script, if Mono is installed
* Make sure `NzbDrone.Console` is set as the startup project
* Run `build.sh` before running
## 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

View File

@@ -16,14 +16,14 @@ install:
build_script:
- ps: ./build-appveyor.ps1
# test: off
test:
assemblies:
- '_tests\*Test.dll'
categories:
except:
- IntegrationTest
- AutomationTest
test: off
#test:
# assemblies:
# - '_tests\*Test.dll'
# categories:
# except:
# - IntegrationTest
# - AutomationTest
artifacts:
- path: '_artifacts\*.zip'
@@ -32,7 +32,7 @@ artifacts:
cache:
- '%USERPROFILE%\.nuget\packages'
- node_modules
- node_modules -> package.json
pull_requests:
do_not_increment_build_number: true

View File

@@ -104,11 +104,13 @@ Task("Compile").Does(() => {
});
Task("Gulp").Does(() => {
Npm
.WithLogLevel(NpmLogLevel.Silent)
.FromPath(".")
.Install()
.RunScript("build");
NpmInstall(new NpmInstallSettings {
LogLevel = NpmLogLevel.Silent,
WorkingDirectory = "./",
Production = true
});
NpmRunScript("build");
});
Task("PackageMono").Does(() => {
@@ -166,8 +168,14 @@ Task("PackageOsx").Does(() => {
// Adding MediaInfo dylib
CopyFiles(sourceFolder + "/Libraries/MediaInfo/*.dylib", outputFolderOsx);
// Chmod as executable
StartProcess(@"C:\cygwin64\bin\chmod.exe", new ProcessSettings()
.WithArguments(args => args
.Append("+x")
.Append(outputFolderOsx + "/Radarr")));
// Adding Startup script
CopyFile("./osx/Sonarr", outputFolderOsx + "/Sonarr");
CopyFile("./osx/Radarr", outputFolderOsx + "/Radarr");
});
Task("PackageOsxApp").Does(() => {
@@ -266,9 +274,9 @@ Task("ArtifactsWindows").Does(() => {
Task("ArtifactsWindowsInstaller").Does(() => {
InnoSetup("./setup/nzbdrone.iss", new InnoSetupSettings {
OutputDirectory = artifactsFolder,
OutputDirectory = artifactsFolder,
ToolPath = "./setup/inno/ISCC.exe"
});
});
});
Task("ArtifactsLinux").Does(() => {

View File

@@ -181,7 +181,7 @@ PackageOsx()
cp $sourceFolder/Libraries/MediaInfo/*.dylib $outputFolderOsx
echo "Adding Startup script"
cp ./osx/Sonarr $outputFolderOsx
cp ./osx/Radarr $outputFolderOsx
echo "##teamcity[progressFinish 'Creating OS X Package']"
}

14
changelog.tpl Normal file
View File

@@ -0,0 +1,14 @@
# Changelog
{{#versions}}
## {{{label}}}
{{#sections}}
### {{{label}}}
{{#commits}}
- {{{subject}}} [{{{author}}}]
{{/commits}}
{{/sections}}
{{/versions}}

44
create_test_cases.py Normal file
View File

@@ -0,0 +1,44 @@
input1 = """Prometheus.Special.Edition.Fan Edit.2012..BRRip.x264.AAC-m2g
Star Wars Episode IV - A New Hope (Despecialized) 1999.mkv
Prometheus.(Special.Edition.Remastered).2012.[Bluray-1080p].mkv
Prometheus Extended 2012
Prometheus Extended Directors Cut Fan Edit 2012
Prometheus Director's Cut 2012
Prometheus Directors Cut 2012
Prometheus.(Extended.Theatrical.Version.IMAX).BluRay.1080p.2012.asdf
2001 A Space Odyssey Director's Cut (1968).mkv
2001: A Space Odyssey (Extended Directors Cut FanEdit) Bluray 1080p 1968
A Fake Movie 2035 Directors 2012.mkv
Blade Runner Director's Cut 2049.mkv
Prometheus 50th Anniversary Edition 2012.mkv
Movie 2in1 2012.mkv
Movie IMAX 2012.mkv"""
output1 = """Special.Edition.Fan Edit BRRip.x264.AAC-m2g
Despecialized mkv
Special.Edition.Remastered Bluray-1080p].mkv
Extended mkv
Extended Directors Cut Fan Edit mkv
Director's Cut mkv
Directors Cut mkv
Extended.Theatrical.Version.IMAX asdf
Director's Cut mkv
Extended Directors Cut FanEdit mkv
Directors mkv
Director's Cut mkv
50th Anniversary Edition mkv
2in1 mkv
IMAX mkv"""
inputs = input1.split("\n")
outputs = output1.split("\n")
real_o = []
for output in outputs:
real_o.append(output.split(" ")[0].replace(".", " ").strip())
count = 0
for inp in inputs:
o = real_o[count]
print "[TestCase(\"{0}\", \"{1}\")]".format(inp, o)
count += 1

View File

@@ -25,7 +25,7 @@ gulp.task('copyHtml', function () {
});
gulp.task('copyContent', function () {
return gulp.src([paths.src.content + '**/*.*', '!**/*.less'])
return gulp.src([paths.src.content + '**/*.*', '!**/*.less', '!**/*.css'])
.pipe(gulp.dest(paths.dest.content))
.pipe(livereload());
});

View File

@@ -5,7 +5,7 @@ var postcss = require('gulp-postcss');
var sourcemaps = require('gulp-sourcemaps');
var autoprefixer = require('autoprefixer-core');
var livereload = require('gulp-livereload');
var cleancss = require('gulp-clean-css');
var print = require('gulp-print');
var paths = require('./paths');
var errorHandler = require('./errorHandler');
@@ -16,6 +16,10 @@ gulp.task('less', function() {
paths.src.content + 'bootstrap.less',
paths.src.content + 'theme.less',
paths.src.content + 'overrides.less',
paths.src.content + 'bootstrap.toggle-switch.css',
paths.src.content + 'fullcalendar.css',
paths.src.content + 'Messenger/messenger.css',
paths.src.content + 'Messenger/messenger.flat.css',
paths.src.root + 'Series/series.less',
paths.src.root + 'Activity/activity.less',
paths.src.root + 'AddSeries/addSeries.less',
@@ -36,12 +40,13 @@ gulp.task('less', function() {
.pipe(sourcemaps.init())
.pipe(less({
dumpLineNumbers : 'false',
compress : true,
yuicompress : true,
compress : false,
yuicompress : false,
ieCompat : true,
strictImports : true
}))
.pipe(postcss([ autoprefixer({ browsers: ['last 2 versions'] }) ]))
.pipe(cleancss())
.on('error', errorHandler.onError)
.pipe(sourcemaps.write(paths.dest.content))
.pipe(gulp.dest(paths.dest.content))

View File

@@ -5,7 +5,7 @@ DIR=$(cd "$(dirname "$0")"; pwd)
#change these values to match your app
EXE_PATH="$DIR/Radarr.exe"
APPNAME="Sonarr"
APPNAME="Radarr"
#set up environment
if [[ -x '/opt/local/bin/mono' ]]; then

View File

@@ -11,11 +11,11 @@
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>Sonarr</string>
<string>Radarr</string>
<key>CFBundleIconFile</key>
<string>radarr.icns</string>
<key>CFBundleIdentifier</key>
<string>com.osx.sonarr.tv</string>
<string>com.osx.radarr.video</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

4190
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "Sonarr",
"name": "Radarr",
"version": "2.0.0",
"description": "Sonarr",
"description": "Radarr",
"main": "main.js",
"scripts": {
"build": "gulp build",
@@ -9,7 +9,7 @@
},
"repository": {
"type": "git",
"url": "git://github.com/Sonarr/Sonarr.git"
"url": "git://github.com/Radarr/Radarr.git"
},
"author": "",
"license": "GPL-3.0",
@@ -20,6 +20,7 @@
"del": "1.2.0",
"gulp": "3.9.0",
"gulp-cached": "1.1.0",
"gulp-clean-css": "^3.0.4",
"gulp-concat": "2.6.0",
"gulp-declare": "0.3.0",
"gulp-handlebars": "3.0.1",

View File

@@ -17,10 +17,10 @@ case "$(uname -s)" in
esac
if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
VERSION="`date +%H:%M:%S`"
YEAR="`date +%Y`"
MONTH="`date +%m`"
DAY="`date +%d`"
VERSION="$(date +%H:%M:%S)"
YEAR="$(date +%Y)"
MONTH="$(date +%m)"
DAY="$(date +%d)"
else
VERSION=$1
BRANCH=$2
@@ -32,10 +32,10 @@ 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
tr -d "\r" < $outputFolderOsxApp/Radarr.app/Contents/MacOS/Radarr > $outputFolderOsxApp/Radarr.app/Contents/MacOS/Radarr2
rm $outputFolderOsxApp/Radarr.app/Contents/MacOS/Radarr
chmod +x $outputFolderOsxApp/Radarr.app/Contents/MacOS/Radarr2
mv $outputFolderOsxApp/Radarr.app/Contents/MacOS/Radarr2 $outputFolderOsxApp/Radarr.app/Contents/MacOS/Radarr >& error.log
if [ $runtime = "dotnet" ] ; then
./7za.exe a Radarr_Windows_$VERSION.zip ./Radarr_Windows_$VERSION/*

1
src/.idea/.idea.NzbDrone/.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
NzbDrone

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ContentModelUserStore">
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.NzbDrone/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.NzbDrone/riderModule.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$/../../../Logo/1024.png" />
<content url="file://$MODULE_DIR$/../../../Logo/64.png" />
<content url="file://$MODULE_DIR$/../.." />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -14,8 +14,10 @@ You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>. */
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Runtime.InteropServices.ComTypes;
using Marr.Data.Converters;
namespace Marr.Data.Parameters
@@ -42,15 +44,25 @@ namespace Marr.Data.Parameters
Type valueType = value.GetType();
// Check for a registered IConverter
IConverter converter = MapRepository.Instance.GetConverter(valueType);
if (converter != null)
//If we have a list of ints, we ignore the converter since we want to do an in statement!
var list = value as List<int>;
if (list != null)
{
Parameter.Value = converter.ToDB(value);
Parameter.Value = $"{string.Join(",", list)}";
}
else
{
Parameter.Value = value;
}
IConverter converter = MapRepository.Instance.GetConverter(valueType);
if (converter != null)
{
Parameter.Value = converter.ToDB(value);
}
else
{
Parameter.Value = value;
}
}
//// Determine the correct DbType based on the passed in value type
//IDbTypeBuilder typeBuilder = MapRepository.Instance.DbTypeBuilder;

View File

@@ -68,5 +68,13 @@ namespace Marr.Data.QGen.Dialects
{
get { return "({0} LIKE '%' + {1} + '%')"; }
}
public virtual string InFormat
{
get
{
return "({0} in ({1}))";
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Text;
using System.Linq;
using System.Text;
using Marr.Data.Mapping;
using Marr.Data.QGen.Dialects;
@@ -129,7 +130,16 @@ namespace Marr.Data.QGen
public void BuildOrderClause(StringBuilder sql)
{
sql.Append(OrderBy.ToString());
}
}
public void BuildGroupBy(StringBuilder sql)
{
var baseTable = this.Tables.First();
var primaryKeyColumn = baseTable.Columns.Single(c => c.ColumnInfo.IsPrimaryKey);
string token = this.Dialect.CreateToken(string.Concat(baseTable.Alias, ".", primaryKeyColumn.ColumnInfo.Name));
sql.AppendFormat(" GROUP BY {0}", token);
}
private string TranslateJoin(JoinType join)
{

View File

@@ -14,8 +14,22 @@ namespace Marr.Data.QGen
public string Generate()
{
StringBuilder sql = new StringBuilder();
BuildSelectCountClause(sql);
if (_innerQuery.IsJoin)
{
sql.Append(" FROM (");
_innerQuery.BuildSelectClause(sql);
_innerQuery.BuildFromClause(sql);
_innerQuery.BuildJoinClauses(sql);
_innerQuery.BuildWhereClause(sql);
_innerQuery.BuildGroupBy(sql);
sql.Append(") ");
return sql.ToString();
}
_innerQuery.BuildFromClause(sql);
_innerQuery.BuildJoinClauses(sql);
_innerQuery.BuildWhereClause(sql);

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq.Expressions;
using System.Data.Common;
@@ -92,6 +93,10 @@ namespace Marr.Data.QGen
case "EndsWith":
Write_EndsWith(expression);
break;
case "In":
Write_In(expression);
break;
default:
string msg = string.Format("'{0}' expressions are not yet implemented in the where clause expression tree parser.", method);
@@ -140,31 +145,47 @@ namespace Marr.Data.QGen
return expression;
}
private object GetRightValue(Expression rightExpression)
private object GetRightValue(Expression expression)
{
object rightValue = null;
var right = rightExpression as ConstantExpression;
if (right == null) // Value is not directly passed in as a constant
var simpleConstExp = expression as ConstantExpression;
if (simpleConstExp == null) // Value is not directly passed in as a constant
{
var rightMemberExp = (rightExpression as MemberExpression);
var parentMemberExpression = rightMemberExp.Expression as MemberExpression;
if (parentMemberExpression != null) // Value is passed in as a property on a parent entity
MemberExpression memberExp = expression as MemberExpression;
ConstantExpression constExp = null;
// Value may be nested in multiple levels of objects/properties, so traverse the MemberExpressions
// until a ConstantExpression property value is found, and then unwind the stack to get the value.
var memberNames = new Stack<string>();
while (memberExp != null)
{
string entityName = (rightMemberExp.Expression as MemberExpression).Member.Name;
var container = ((rightMemberExp.Expression as MemberExpression).Expression as ConstantExpression).Value;
var entity = _repos.ReflectionStrategy.GetFieldValue(container, entityName);
rightValue = _repos.ReflectionStrategy.GetFieldValue(entity, rightMemberExp.Member.Name);
memberNames.Push(memberExp.Member.Name);
// Function calls are not supported - user needs to simplify their Where expression.
var methodExp = memberExp.Expression as MethodCallExpression;
if (methodExp != null)
{
var errMsg = string.Format("Function calls are not supported by the Where clause expression parser. Please evaluate your function call, '{0}', manually and then use the resulting paremeter value in your Where expression.", methodExp.Method.Name);
throw new NotSupportedException(errMsg);
}
constExp = memberExp.Expression as ConstantExpression;
memberExp = memberExp.Expression as MemberExpression;
}
else // Value is passed in as a variable
object entity = constExp.Value;
while (memberNames.Count > 0)
{
var parent = (rightMemberExp.Expression as ConstantExpression).Value;
rightValue = _repos.ReflectionStrategy.GetFieldValue(parent, rightMemberExp.Member.Name);
string entityName = memberNames.Pop();
entity = _repos.ReflectionStrategy.GetFieldValue(entity, entityName);
}
rightValue = entity;
}
else // Value is passed in directly as a constant
{
rightValue = right.Value;
rightValue = simpleConstExp.Value;
}
return rightValue;
@@ -238,6 +259,17 @@ namespace Marr.Data.QGen
_sb.AppendFormat(_dialect.ContainsFormat, fqColumn, paramName);
}
private void Write_In(MethodCallExpression body)
{
object value = GetRightValue(body.Arguments[1]);
//string paramName = string.Concat(_paramPrefix, "P", _command.Parameters.Count.ToString());
//var parameter = new ParameterChainMethods(_command, paramName, value).Parameter;
MemberExpression memberExp = (body.Arguments[0] as MemberExpression);
string fqColumn = GetFullyQualifiedColumnName(memberExp.Member, memberExp.Expression.Type);
_sb.AppendFormat(_dialect.InFormat, fqColumn, string.Join(",", value as List<int>));
}
private void Write_StartsWith(MethodCallExpression body)
{
// Add parameter to Command.Parameters

View File

@@ -70,6 +70,7 @@ namespace NzbDrone.Api.Authentication
{
RedirectUrl = _configFileProvider.UrlBase + "/login",
UserMapper = _authenticationService,
Path = _configFileProvider.UrlBase,
CryptographyConfiguration = cryptographyConfiguration
});
}

View File

@@ -1,9 +1,10 @@
using Nancy;
using Nancy;
using System;
using System.Collections.Generic;
using System.Linq;
using Ical.Net;
using Ical.Net.DataTypes;
using Ical.Net.General;
using Ical.Net.Interfaces.Serialization;
using Ical.Net.Serialization;
using Ical.Net.Serialization.iCalendar.Factory;
@@ -86,6 +87,10 @@ namespace NzbDrone.Api.Calendar
ProductId = "-//radarr.video//Radarr//EN"
};
var calendarName = "Radarr Movies Calendar";
calendar.AddProperty(new CalendarProperty("NAME", calendarName));
calendar.AddProperty(new CalendarProperty("X-WR-CALNAME", calendarName));
foreach (var movie in movies.OrderBy(v => v.Added))
{
if (tags.Any() && tags.None(movie.Tags.Contains))
@@ -114,8 +119,10 @@ namespace NzbDrone.Api.Calendar
occurrence.End = new CalDateTime(movie.InCinemas.Value.AddMinutes(movie.Runtime)) { HasTime = true };
}
break;
case MovieStatusType.Announced:
continue; // no date
default:
if (movie.PhysicalRelease != null)
{

View File

@@ -41,12 +41,22 @@ namespace NzbDrone.Api.ClientSchema
};
var value = propertyInfo.GetValue(model, null);
if (propertyInfo.PropertyType.HasAttribute<FlagsAttribute>())
{
int intVal = (int)value;
value = Enum.GetValues(propertyInfo.PropertyType)
.Cast<int>()
.Where(f=> (f & intVal) == f)
.ToList();
}
if (value != null)
{
field.Value = value;
}
if (fieldAttribute.Type == FieldType.Select)
if (fieldAttribute.Type == FieldType.Select || fieldAttribute.Type == FieldType.Tag)
{
field.SelectOptions = GetSelectOptions(fieldAttribute.SelectOptions);
}
@@ -131,6 +141,12 @@ namespace NzbDrone.Api.ClientSchema
propertyInfo.SetValue(target, value, null);
}
else if (propertyInfo.PropertyType.HasAttribute<FlagsAttribute>())
{
int value = field.Value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s)).Sum();
propertyInfo.SetValue(target, value, null);
}
else
{
@@ -150,7 +166,7 @@ namespace NzbDrone.Api.ClientSchema
private static List<SelectOption> GetSelectOptions(Type selectOptions)
{
if (selectOptions == typeof(Profile))
if (selectOptions == null || selectOptions == typeof(Profile))
{
return new List<SelectOption>();
}
@@ -165,7 +181,7 @@ namespace NzbDrone.Api.ClientSchema
var options = from Enum e in Enum.GetValues(selectOptions)
select new SelectOption { Value = Convert.ToInt32(e), Name = e.ToString() };
return options.OrderBy(o => o.Value).ToList();
return options.OrderBy(o => o.Name).ToList();
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Validation;
using NzbDrone.Common;
@@ -17,14 +18,17 @@ namespace NzbDrone.Api.Commands
{
private readonly IManageCommandQueue _commandQueueManager;
private readonly IServiceFactory _serviceFactory;
private readonly Logger _logger;
public CommandModule(IManageCommandQueue commandQueueManager,
IBroadcastSignalRMessage signalRBroadcaster,
IServiceFactory serviceFactory)
IServiceFactory serviceFactory,
Logger logger)
: base(signalRBroadcaster)
{
_commandQueueManager = commandQueueManager;
_serviceFactory = serviceFactory;
_logger = logger;
GetResourceById = GetCommand;
CreateResource = StartCommand;
@@ -41,7 +45,13 @@ namespace NzbDrone.Api.Commands
private int StartCommand(CommandResource commandResource)
{
var commandType = _serviceFactory.GetImplementations(typeof(Command))
.Single(c => c.Name.Replace("Command", "").Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
.SingleOrDefault(c => c.Name.Replace("Command", "").Equals(commandResource.Name, StringComparison.InvariantCultureIgnoreCase));
if (commandType == null)
{
_logger.Error("Found no matching command for {0}", commandResource.Name);
return 0;
}
dynamic command = Request.Body.FromJson(commandType);
command.Trigger = CommandTrigger.Manual;

View File

@@ -1,5 +1,6 @@
using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Config
{
@@ -12,6 +13,7 @@ namespace NzbDrone.Api.Config
public int AvailabilityDelay { get; set; }
public bool AllowHardcodedSubs { get; set; }
public string WhitelistedHardcodedSubs { get; set; }
public ParsingLeniencyType ParsingLeniency { get; set; }
}
public static class IndexerConfigResourceMapper
@@ -27,7 +29,7 @@ namespace NzbDrone.Api.Config
AvailabilityDelay = model.AvailabilityDelay,
AllowHardcodedSubs = model.AllowHardcodedSubs,
WhitelistedHardcodedSubs = model.WhitelistedHardcodedSubs,
ParsingLeniency = model.ParsingLeniency,
};
}
}

View File

@@ -11,6 +11,8 @@ namespace NzbDrone.Api.Config
public bool AutoDownloadPropers { get; set; }
public bool CreateEmptySeriesFolders { get; set; }
public FileDateType FileDate { get; set; }
public bool AutoRenameFolders { get; set; }
public bool PathsDefaultStatic { get; set; }
public bool SetPermissionsLinux { get; set; }
public string FileChmod { get; set; }
@@ -35,6 +37,8 @@ namespace NzbDrone.Api.Config
AutoDownloadPropers = model.AutoDownloadPropers,
CreateEmptySeriesFolders = model.CreateEmptySeriesFolders,
FileDate = model.FileDate,
AutoRenameFolders = model.AutoRenameFolders,
PathsDefaultStatic = model.PathsDefaultStatic,
SetPermissionsLinux = model.SetPermissionsLinux,
FileChmod = model.FileChmod,

View File

@@ -23,6 +23,8 @@ namespace NzbDrone.Api.Extensions.Pipelines
private void Handle(NancyContext context)
{
if (context.Request.Method == "OPTIONS") return;
if (_cacheableSpecification.IsCacheable(context))
{
context.Response.Headers.EnableCache();
@@ -33,4 +35,4 @@ namespace NzbDrone.Api.Extensions.Pipelines
}
}
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Linq;
using Nancy;
using Nancy.Bootstrapper;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Api.Extensions.Pipelines
{
@@ -11,10 +12,25 @@ namespace NzbDrone.Api.Extensions.Pipelines
public void Register(IPipelines pipelines)
{
pipelines.AfterRequest.AddItemToEndOfPipeline((Action<NancyContext>) Handle);
pipelines.BeforeRequest.AddItemToEndOfPipeline(HandleRequest);
pipelines.AfterRequest.AddItemToEndOfPipeline(HandleResponse);
}
private void Handle(NancyContext context)
private Response HandleRequest(NancyContext context)
{
if (context == null || context.Request.Method != "OPTIONS")
{
return null;
}
var response = new Response()
.WithStatusCode(HttpStatusCode.OK)
.WithContentType("");
ApplyResponseHeaders(response, context.Request);
return response;
}
private void HandleResponse(NancyContext context)
{
if (context == null || context.Response.Headers.ContainsKey(AccessControlHeaders.AllowOrigin))
{
@@ -26,21 +42,39 @@ namespace NzbDrone.Api.Extensions.Pipelines
private static void ApplyResponseHeaders(Response response, Request request)
{
var allowedMethods = "GET, OPTIONS, PATCH, POST, PUT, DELETE";
if (response.Headers.ContainsKey("Allow"))
if (request.IsApiRequest())
{
allowedMethods = response.Headers["Allow"];
// Allow Cross-Origin access to the API since it's protected with the apikey, and nothing else.
ApplyCorsResponseHeaders(response, request, "*", "GET, OPTIONS, PATCH, POST, PUT, DELETE");
}
var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]);
response.Headers.Add(AccessControlHeaders.AllowOrigin, "*");
response.Headers.Add(AccessControlHeaders.AllowMethods, allowedMethods);
if (request.Headers[AccessControlHeaders.RequestHeaders].Any())
else if (request.IsSharedContentRequest())
{
response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders);
// Allow Cross-Origin access to specific shared content such as mediacovers and images.
ApplyCorsResponseHeaders(response, request, "*", "GET, OPTIONS");
}
// Disallow Cross-Origin access for any other route.
}
private static void ApplyCorsResponseHeaders(Response response, Request request, string allowOrigin, string allowedMethods)
{
response.Headers.Add(AccessControlHeaders.AllowOrigin, allowOrigin);
if (request.Method == "OPTIONS")
{
if (response.Headers.ContainsKey("Allow"))
{
allowedMethods = response.Headers["Allow"];
}
response.Headers.Add(AccessControlHeaders.AllowMethods, allowedMethods);
if (request.Headers[AccessControlHeaders.RequestHeaders].Any())
{
var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]);
response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders);
}
}
}
}

View File

@@ -33,7 +33,8 @@ namespace NzbDrone.Api.Extensions.Pipelines
try
{
if (
!response.ContentType.Contains("image")
response.Contents != Response.NoBody
&& !response.ContentType.Contains("image")
&& !response.ContentType.Contains("font")
&& request.Headers.AcceptEncoding.Any(x => x.Contains("gzip"))
&& !AlreadyGzipEncoded(response)
@@ -80,4 +81,4 @@ namespace NzbDrone.Api.Extensions.Pipelines
return false;
}
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using Nancy;
using Nancy.Bootstrapper;
using Nancy.Responses;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Extensions.Pipelines
{
public class UrlBasePipeline : IRegisterNancyPipeline
{
private readonly string _urlBase;
public UrlBasePipeline(IConfigFileProvider configFileProvider)
{
_urlBase = configFileProvider.UrlBase;
}
public int Order => 99;
public void Register(IPipelines pipelines)
{
if (_urlBase.IsNotNullOrWhiteSpace())
{
pipelines.BeforeRequest.AddItemToStartOfPipeline((Func<NancyContext, Response>) Handle);
}
}
private Response Handle(NancyContext context)
{
var basePath = context.Request.Url.BasePath;
if (basePath.IsNullOrWhiteSpace())
{
return new RedirectResponse($"{_urlBase}{context.Request.Path}{context.Request.Url.Query}");
}
if (_urlBase != basePath)
{
return new NotFoundResponse();
}
return null;
}
}
}

View File

@@ -36,5 +36,11 @@ namespace NzbDrone.Api.Extensions
{
return request.Path.StartsWith("/Content/", StringComparison.InvariantCultureIgnoreCase);
}
public static bool IsSharedContentRequest(this Request request)
{
return request.Path.StartsWith("/MediaCover/", StringComparison.InvariantCultureIgnoreCase) ||
request.Path.StartsWith("/Content/Images/", StringComparison.InvariantCultureIgnoreCase);
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Text.RegularExpressions;
using Nancy;
@@ -17,7 +17,7 @@ namespace NzbDrone.Api.Frontend.Mappers
private readonly IAnalyticsService _analyticsService;
private readonly Func<ICacheBreakerProvider> _cacheBreakProviderFactory;
private readonly string _indexPath;
private static readonly Regex ReplaceRegex = new Regex(@"(?:(?<attribute>href|src)=\"")(?<path>.*?(?<extension>css|js|png|ico|ics))(?:\"")(?:\s(?<nohash>data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ReplaceRegex = new Regex(@"(?:(?<attribute>href|src|content)=\"")(?<path>.*?(?<extension>css|js|png|ico|ics|svg|json|xml))(?:\"")(?:\s(?<nohash>data-no-hash))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static string API_KEY;
private static string URL_BASE;
@@ -49,7 +49,12 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return !resourceUrl.Contains(".") && !resourceUrl.StartsWith("/login");
resourceUrl = resourceUrl.ToLowerInvariant();
return !resourceUrl.StartsWith("/content") &&
!resourceUrl.StartsWith("/mediacover") &&
!resourceUrl.Contains(".") &&
!resourceUrl.StartsWith("/login");
}
public override Response GetResponse(string resourceUrl)
@@ -113,4 +118,4 @@ namespace NzbDrone.Api.Frontend.Mappers
return _generatedContent;
}
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using NLog;
@@ -42,7 +43,7 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return resourceUrl.StartsWith("/MediaCover");
return resourceUrl.StartsWith("/MediaCover", StringComparison.InvariantCultureIgnoreCase);
}
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using NLog;
using NzbDrone.Common.Disk;
@@ -28,7 +29,9 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return resourceUrl.StartsWith("/Content") ||
resourceUrl = resourceUrl.ToLowerInvariant();
return resourceUrl.StartsWith("/content") ||
resourceUrl.EndsWith(".js") ||
resourceUrl.EndsWith(".map") ||
resourceUrl.EndsWith(".css") ||
@@ -37,4 +40,4 @@ namespace NzbDrone.Api.Frontend.Mappers
resourceUrl.EndsWith("oauth.html");
}
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy.Responses;
using NLog;
using Nancy;
using NzbDrone.Api.Frontend.Mappers;
@@ -38,20 +37,6 @@ namespace NzbDrone.Api.Frontend
return new NotFoundResponse();
}
//Redirect to the subfolder if the request went to the base URL
if (path.Equals("/"))
{
var urlBase = _configFileProvider.UrlBase;
if (!string.IsNullOrEmpty(urlBase))
{
if (Request.Url.BasePath != urlBase)
{
return new RedirectResponse(urlBase + "/");
}
}
}
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
if (mapper != null)

View File

@@ -46,7 +46,7 @@ namespace NzbDrone.Api.Indexers
GetResourceAll = GetReleases;
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>());
PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
//PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
PostValidator.RuleFor(s => s.Guid).NotEmpty();
_remoteEpisodeCache = cacheManager.GetCache<RemoteEpisode>(GetType(), "remoteEpisodes");
@@ -70,7 +70,7 @@ namespace NzbDrone.Api.Indexers
try
{
_downloadService.DownloadReport(remoteMovie);
_downloadService.DownloadReport(remoteMovie, false);
}
catch (ReleaseDownloadException ex)
{

View File

@@ -8,6 +8,7 @@ using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.DecisionEngine;
using System.Linq;
using NzbDrone.Core.Datastore.Migration;
namespace NzbDrone.Api.Indexers
{
@@ -29,8 +30,8 @@ namespace NzbDrone.Api.Indexers
public bool FullSeason { get; set; }
public int SeasonNumber { get; set; }
public Language Language { get; set; }
public string AirDate { get; set; }
public string SeriesTitle { get; set; }
public int Year { get; set; }
public string MovieTitle { get; set; }
public int[] EpisodeNumbers { get; set; }
public int[] AbsoluteEpisodeNumbers { get; set; }
public bool Approved { get; set; }
@@ -43,8 +44,9 @@ namespace NzbDrone.Api.Indexers
public string CommentUrl { get; set; }
public string DownloadUrl { get; set; }
public string InfoUrl { get; set; }
public bool DownloadAllowed { get; set; }
public MappingResultType MappingResult { get; set; }
public int ReleaseWeight { get; set; }
public int SuspectedMovieId { get; set; }
public IEnumerable<string> IndexerFlags { get; set; }
@@ -88,11 +90,12 @@ 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;
var mappingResult = MappingResultType.Success;
if (model.IsForMovie)
{
downloadAllowed = model.RemoteMovie.DownloadAllowed;
mappingResult = model.RemoteMovie.MappingResult;
var parsedMovieInfo = model.RemoteMovie.ParsedMovieInfo;
var movieId = model.RemoteMovie.Movie?.Id ?? 0;
return new ReleaseResource
{
@@ -111,8 +114,8 @@ namespace NzbDrone.Api.Indexers
//FullSeason = parsedMovieInfo.FullSeason,
//SeasonNumber = parsedMovieInfo.SeasonNumber,
Language = parsedMovieInfo.Language,
AirDate = "",
SeriesTitle = parsedMovieInfo.MovieTitle,
Year = parsedMovieInfo.Year,
MovieTitle = parsedMovieInfo.MovieTitle,
EpisodeNumbers = new int[0],
AbsoluteEpisodeNumbers = new int[0],
Approved = model.Approved,
@@ -125,8 +128,10 @@ namespace NzbDrone.Api.Indexers
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = downloadAllowed,
MappingResult = mappingResult,
//ReleaseWeight
SuspectedMovieId = movieId,
MagnetUrl = torrentInfo.MagnetUrl,
InfoHash = torrentInfo.InfoHash,
@@ -161,8 +166,8 @@ namespace NzbDrone.Api.Indexers
FullSeason = parsedEpisodeInfo.FullSeason,
SeasonNumber = parsedEpisodeInfo.SeasonNumber,
Language = parsedEpisodeInfo.Language,
AirDate = parsedEpisodeInfo.AirDate,
SeriesTitle = parsedEpisodeInfo.SeriesTitle,
//AirDate = parsedEpisodeInfo.AirDate,
//SeriesTitle = parsedEpisodeInfo.SeriesTitle,
EpisodeNumbers = parsedEpisodeInfo.EpisodeNumbers,
AbsoluteEpisodeNumbers = parsedEpisodeInfo.AbsoluteEpisodeNumbers,
Approved = model.Approved,
@@ -175,7 +180,7 @@ namespace NzbDrone.Api.Indexers
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl,
DownloadAllowed = downloadAllowed,
//DownloadAllowed = downloadAllowed,
//ReleaseWeight
MagnetUrl = torrentInfo.MagnetUrl,

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movie;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Common.Crypto;
@@ -16,8 +17,9 @@ namespace NzbDrone.Api.ManualImport
public string Name { get; set; }
public long Size { get; set; }
public SeriesResource Series { get; set; }
public MovieResource Movie { get; set; }
public int? SeasonNumber { get; set; }
public List<EpisodeResource> Episodes { get; set; }
public List<Episodes.EpisodeResource> Episodes { get; set; }
public QualityModel Quality { get; set; }
public int QualityWeight { get; set; }
public string DownloadId { get; set; }
@@ -39,6 +41,7 @@ namespace NzbDrone.Api.ManualImport
Name = model.Name,
Size = model.Size,
Series = model.Series.ToResource(),
Movie = model.Movie.ToResource(),
SeasonNumber = model.SeasonNumber,
Episodes = model.Episodes.ToResource(),
Quality = model.Quality,

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Marr.Data;
using Nancy;
using NzbDrone.Api;
using NzbDrone.Api.Movie;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.MetadataSource.RadarrAPI;
using NzbDrone.Core.Movies.AlternativeTitles;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Api.Movie
{
public class AlternativeTitleModule : NzbDroneRestModule<AlternativeTitleResource>
{
private readonly IAlternativeTitleService _altTitleService;
private readonly IMovieService _movieService;
private readonly IRadarrAPIClient _radarrApi;
private readonly IEventAggregator _eventAggregator;
public AlternativeTitleModule(IAlternativeTitleService altTitleService, IMovieService movieService, IRadarrAPIClient radarrApi, IEventAggregator eventAggregator)
: base("/alttitle")
{
_altTitleService = altTitleService;
_movieService = movieService;
_radarrApi = radarrApi;
CreateResource = AddTitle;
GetResourceById = GetTitle;
_eventAggregator = eventAggregator;
}
private int AddTitle(AlternativeTitleResource altTitle)
{
var title = altTitle.ToModel();
var movie = _movieService.GetMovie(altTitle.MovieId);
var newTitle = _radarrApi.AddNewAlternativeTitle(title, movie.TmdbId);
var addedTitle = _altTitleService.AddAltTitle(newTitle, movie);
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
return addedTitle.Id;
}
private AlternativeTitleResource GetTitle(int id)
{
return _altTitleService.GetById(id).ToResource();
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Marr.Data;
using Nancy;
using NzbDrone.Api;
using NzbDrone.Api.Movie;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.MetadataSource.RadarrAPI;
using NzbDrone.Core.Movies.AlternativeTitles;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Api.Movie
{
public class AlternativeYearModule : NzbDroneRestModule<AlternativeYearResource>
{
private readonly IMovieService _movieService;
private readonly IRadarrAPIClient _radarrApi;
private readonly ICached<int> _yearCache;
private readonly IEventAggregator _eventAggregator;
public AlternativeYearModule(IMovieService movieService, IRadarrAPIClient radarrApi, ICacheManager cacheManager, IEventAggregator eventAggregator)
: base("/altyear")
{
_movieService = movieService;
_radarrApi = radarrApi;
CreateResource = AddYear;
GetResourceById = GetYear;
_yearCache = cacheManager.GetCache<int>(GetType(), "altYears");
_eventAggregator = eventAggregator;
}
private int AddYear(AlternativeYearResource altYear)
{
var id = new Random().Next();
_yearCache.Set(id.ToString(), altYear.Year, TimeSpan.FromMinutes(1));
var movie = _movieService.GetMovie(altYear.MovieId);
var newYear = _radarrApi.AddNewAlternativeYear(altYear.Year, movie.TmdbId);
movie.SecondaryYear = newYear.Year;
movie.SecondaryYearSourceId = newYear.SourceId;
_movieService.UpdateMovie(movie);
_eventAggregator.PublishEvent(new MovieUpdatedEvent(movie));
return id;
}
private AlternativeYearResource GetYear(int id)
{
return new AlternativeYearResource
{
Year = _yearCache.Find(id.ToString())
};
}
}
}

View File

@@ -0,0 +1,75 @@
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;
using NzbDrone.Core.Movies.AlternativeTitles;
using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Movie
{
public class AlternativeYearResource : RestResource
{
public AlternativeYearResource()
{
}
//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 int Year { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
}
/*public static class AlternativeYearResourceMapper
{
/*public static AlternativeYearResource ToResource(this AlternativeTitle model)
{
if (model == null) return null;
AlternativeTitleResource resource = null;
return new AlternativeTitleResource
{
Id = model.Id,
SourceType = model.SourceType,
MovieId = model.MovieId,
Title = model.Title,
SourceId = model.SourceId,
Votes = model.Votes,
VoteCount = model.VoteCount,
Language = model.Language
};
}
public static AlternativeTitle ToModel(this AlternativeTitleResource resource)
{
if (resource == null) return null;
return new AlternativeTitle
{
Id = resource.Id,
SourceType = resource.SourceType,
MovieId = resource.MovieId,
Title = resource.Title,
SourceId = resource.SourceId,
Votes = resource.Votes,
VoteCount = resource.VoteCount,
Language = resource.Language
};
}
public static List<AlternativeTitleResource> ToResource(this IEnumerable<AlternativeTitle> movies)
{
return movies.Select(ToResource).ToList();
}
}*/
}

View File

@@ -90,7 +90,7 @@ namespace NzbDrone.Api.Movie
return mappedMovie;
}
var parsedTitle = Parser.ParseMoviePath(f.Name);
var parsedTitle = Parser.ParseMoviePath(f.Name, false);
if (parsedTitle == null)
{
m = new Core.Tv.Movie

View File

@@ -1,7 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using Nancy.Responses;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.REST;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Movie
@@ -15,6 +18,7 @@ namespace NzbDrone.Api.Movie
{
_movieService = movieService;
Put["/"] = Movie => SaveAll();
Put["/delete"] = Movie => DeleteSelected();
}
private Response SaveAll()
@@ -27,5 +31,33 @@ namespace NzbDrone.Api.Movie
.ToResource()
.AsResponse(HttpStatusCode.Accepted);
}
private Response DeleteSelected()
{
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);
}
var ids = Request.Body.FromJson<List<int>>();
foreach (var id in ids)
{
_movieService.DeleteMovie(id, deleteFiles, addExclusion);
}
return new Response
{
StatusCode = HttpStatusCode.Accepted
};
}
}
}

View File

@@ -46,11 +46,14 @@ namespace NzbDrone.Api.EpisodeFiles
return movie.ToResource();
}
private void SetQuality(MovieFileResource movieFileResource)
{
{
var movieFile = _mediaFileService.GetMovie(movieFileResource.Id);
movieFile.Quality = movieFileResource.Quality;
_mediaFileService.Update(movieFile);
BroadcastResourceChange(ModelAction.Updated, movieFile.Id);
}
private void DeleteMovieFile(int id)

View File

@@ -34,7 +34,6 @@ namespace NzbDrone.Api
RegisterPipelines(pipelines);
container.Resolve<DatabaseTarget>().Register();
container.Resolve<IEventAggregator>().PublishEvent(new ApplicationStartedEvent());
}
private void RegisterPipelines(IPipelines pipelines)
@@ -56,4 +55,4 @@ namespace NzbDrone.Api
protected override byte[] FavIcon => null;
}
}
}

View File

@@ -0,0 +1,45 @@
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.NetImport;
using NzbDrone.Core.NetImport.ImportExclusions;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.NetImport
{
public class ImportExclusionsModule : NzbDroneRestModule<ImportExclusionsResource>
{
private readonly IImportExclusionsService _exclusionService;
public ImportExclusionsModule(NetImportFactory netImportFactory, IImportExclusionsService exclusionService) : base("exclusions")
{
_exclusionService = exclusionService;
GetResourceAll = GetAll;
CreateResource = AddExclusion;
DeleteResource = RemoveExclusion;
GetResourceById = GetById;
}
public List<ImportExclusionsResource> GetAll()
{
return _exclusionService.GetAllExclusions().ToResource();
}
public ImportExclusionsResource GetById(int id)
{
return _exclusionService.GetById(id).ToResource();
}
public int AddExclusion(ImportExclusionsResource exclusionResource)
{
var model = exclusionResource.ToModel();
return _exclusionService.AddExclusion(model).Id;
}
public void RemoveExclusion (int id)
{
_exclusionService.RemoveExclusion(new ImportExclusion { Id = id });
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.NetImport;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.NetImport
{
public class ImportExclusionsResource : ProviderResource
{
//public int Id { get; set; }
public int TmdbId { get; set; }
public string MovieTitle { get; set; }
public int MovieYear { get; set; }
}
public static class ImportExclusionsResourceMapper
{
public static ImportExclusionsResource ToResource(this Core.NetImport.ImportExclusions.ImportExclusion model)
{
if (model == null) return null;
return new ImportExclusionsResource
{
Id = model.Id,
TmdbId = model.TmdbId,
MovieTitle = model.MovieTitle,
MovieYear = model.MovieYear
};
}
public static List<ImportExclusionsResource> ToResource(this IEnumerable<Core.NetImport.ImportExclusions.ImportExclusion> exclusions)
{
return exclusions.Select(ToResource).ToList();
}
public static Core.NetImport.ImportExclusions.ImportExclusion ToModel(this ImportExclusionsResource resource)
{
return new Core.NetImport.ImportExclusions.ImportExclusion
{
TmdbId = resource.TmdbId,
MovieTitle = resource.MovieTitle,
MovieYear = resource.MovieYear
};
}
}
}

View File

@@ -9,7 +9,7 @@ namespace NzbDrone.Api.NetImport
{
public NetImportModule(NetImportFactory netImportFactory) : base(netImportFactory, "netimport")
{
PostValidator.RuleFor(c => c.RootFolderPath).NotNull();
PostValidator.RuleFor(c => c.RootFolderPath).IsValidPath();
PostValidator.RuleFor(c => c.MinimumAvailability).NotNull();
PostValidator.RuleFor(c => c.ProfileId).NotNull();
}

View File

@@ -113,11 +113,15 @@
<Compile Include="Config\NetImportConfigResource.cs" />
<Compile Include="Extensions\AccessControlHeaders.cs" />
<Compile Include="Extensions\Pipelines\CorsPipeline.cs" />
<Compile Include="Extensions\Pipelines\UrlBasePipeline.cs" />
<Compile Include="Extensions\Pipelines\RequestLoggingPipeline.cs" />
<Compile Include="Frontend\Mappers\LoginHtmlMapper.cs" />
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
<Compile Include="Indexers\ReleaseModuleBase.cs" />
<Compile Include="Indexers\ReleasePushModule.cs" />
<Compile Include="Movies\AlternativeTitleModule.cs" />
<Compile Include="Movies\AlternativeYearResource.cs" />
<Compile Include="Movies\AlternativeYearModule.cs" />
<Compile Include="Movies\MovieModuleWithSignalR.cs" />
<Compile Include="Movies\MovieBulkImportModule.cs" />
<Compile Include="Movies\MovieFileModule.cs" />
@@ -239,7 +243,7 @@
<Compile Include="RootFolders\RootFolderModule.cs" />
<Compile Include="RootFolders\RootFolderResource.cs" />
<Compile Include="SeasonPass\SeasonPassResource.cs" />
<Compile Include="Series\AlternateTitleResource.cs" />
<Compile Include="Series\AlternativeTitleResource.cs" />
<Compile Include="Series\MovieFileResource.cs" />
<Compile Include="Series\FetchMovieListModule.cs" />
<Compile Include="Series\SeasonResource.cs" />
@@ -270,6 +274,9 @@
<Compile Include="Wanted\MissingModule.cs" />
<Compile Include="Wanted\MovieCutoffModule.cs" />
<Compile Include="Wanted\MovieMissingModule.cs" />
<Compile Include="Series\MovieDiscoverModule.cs" />
<Compile Include="NetImport\ImportExclusionsModule.cs" />
<Compile Include="NetImport\ImportExclusionsResource.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

View File

@@ -105,7 +105,7 @@ namespace NzbDrone.Api.Queue
throw new NotFoundException();
}
_downloadService.DownloadReport(pendingRelease.RemoteMovie);
_downloadService.DownloadReport(pendingRelease.RemoteMovie, false);
return resource.AsResponse();
}

View File

@@ -124,7 +124,7 @@ namespace NzbDrone.Api.REST
Get[ROOT_ROUTE] = options =>
{
var pagingSpec = ReadPagingResourceFromRequest();
if (pagingSpec.Page == 0 && pagingSpec.PageSize == 0)
if ((pagingSpec.Page == 0 && pagingSpec.PageSize == 0) || pagingSpec.PageSize == -1)
{
var all = GetResourceAll();
return all.AsResponse();

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.RootFolders;
@@ -9,6 +9,7 @@ namespace NzbDrone.Api.RootFolders
{
public string Path { get; set; }
public long? FreeSpace { get; set; }
public long? TotalSpace { get; set; }
public List<UnmappedFolder> UnmappedFolders { get; set; }
}
@@ -25,6 +26,7 @@ namespace NzbDrone.Api.RootFolders
Path = model.Path,
FreeSpace = model.FreeSpace,
TotalSpace = model.TotalSpace,
UnmappedFolders = model.UnmappedFolders
};
}
@@ -48,4 +50,4 @@ namespace NzbDrone.Api.RootFolders
return models.Select(ToResource).ToList();
}
}
}
}

View File

@@ -1,9 +0,0 @@
namespace NzbDrone.Api.Series
{
public class AlternateTitleResource
{
public string Title { get; set; }
public int? SeasonNumber { get; set; }
public int? SceneSeasonNumber { get; set; }
}
}

View File

@@ -0,0 +1,81 @@
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;
using NzbDrone.Core.Movies.AlternativeTitles;
using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Movie
{
public class AlternativeTitleResource : RestResource
{
public AlternativeTitleResource()
{
}
//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 SourceType SourceType { get; set; }
public int MovieId { get; set; }
public string Title { get; set; }
public string CleanTitle { get; set; }
public int SourceId { get; set; }
public int Votes { get; set; }
public int VoteCount { get; set; }
public Language Language { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
}
public static class AlternativeTitleResourceMapper
{
public static AlternativeTitleResource ToResource(this AlternativeTitle model)
{
if (model == null) return null;
AlternativeTitleResource resource = null;
return new AlternativeTitleResource
{
Id = model.Id,
SourceType = model.SourceType,
MovieId = model.MovieId,
Title = model.Title,
SourceId = model.SourceId,
Votes = model.Votes,
VoteCount = model.VoteCount,
Language = model.Language
};
}
public static AlternativeTitle ToModel(this AlternativeTitleResource resource)
{
if (resource == null) return null;
return new AlternativeTitle
{
Id = resource.Id,
SourceType = resource.SourceType,
MovieId = resource.MovieId,
Title = resource.Title,
SourceId = resource.SourceId,
Votes = resource.Votes,
VoteCount = resource.VoteCount,
Language = resource.Language
};
}
public static List<AlternativeTitleResource> ToResource(this IEnumerable<AlternativeTitle> movies)
{
return movies.Select(ToResource).ToList();
}
}
}

View File

@@ -0,0 +1,63 @@
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;
using NzbDrone.Core.NetImport;
using NzbDrone.Api.NetImport;
namespace NzbDrone.Api.Movie
{
public class MovieDiscoverModule : NzbDroneRestModule<MovieResource>
{
private readonly IDiscoverNewMovies _searchProxy;
private readonly INetImportFactory _netImportFactory;
public MovieDiscoverModule(IDiscoverNewMovies searchProxy, INetImportFactory netImportFactory)
: base("/movies/discover")
{
_searchProxy = searchProxy;
_netImportFactory = netImportFactory;
Get["/lists"] = x => GetLists();
Get["/{action?recommendations}"] = x => Search(x.action);
}
private Response Search(string action)
{
var imdbResults = _searchProxy.DiscoverNewMovies(action);
return MapToResource(imdbResults).AsResponse();
}
private Response GetLists()
{
var lists = _netImportFactory.Discoverable();
return lists.Select(definition => {
var resource = new NetImportResource();
resource.Id = definition.Definition.Id;
resource.Name = definition.Definition.Name;
return resource;
}).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

@@ -44,14 +44,14 @@ namespace NzbDrone.Api.Movie
MovieResource movie = null;
if (model.Movie != null)
/*if (model.Movie != null)
{
model.Movie.LazyLoad();
//model.Movie.LazyLoad();
if (model.Movie.Value != null)
{
//movie = model.Movie.Value.ToResource();
}
}
}*/
return new MovieFileResource
{
@@ -60,6 +60,7 @@ namespace NzbDrone.Api.Movie
Path = model.Path,
Size = model.Size,
DateAdded = model.DateAdded,
SceneName = model.SceneName,
ReleaseGroup = model.ReleaseGroup,
Quality = model.Quality,
Movie = movie,

View File

@@ -17,6 +17,8 @@ using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Validation;
using NzbDrone.SignalR;
using NzbDrone.Core.Datastore;
using Microsoft.CSharp.RuntimeBinder;
using Nancy;
namespace NzbDrone.Api.Movie
{
@@ -58,9 +60,12 @@ namespace NzbDrone.Api.Movie
GetResourceAll = AllMovie;
GetResourcePaged = GetMoviePaged;
GetResourceById = GetMovie;
Get[TITLE_SLUG_ROUTE] = (options) => {
return ReqResExtensions.AsResponse(GetByTitleSlug(options.slug));
};
Get[TITLE_SLUG_ROUTE] = GetByTitleSlug; /*(options) => {
return ReqResExtensions.AsResponse(GetByTitleSlug(options.slug), Nancy.HttpStatusCode.OK);
};*/
CreateResource = AddMovie;
UpdateResource = UpdateMovie;
DeleteResource = DeleteMovie;
@@ -127,8 +132,8 @@ namespace NzbDrone.Api.Movie
var resource = movies.ToResource();
MapCoversToLocal(resource);
FetchAndLinkMovieStatistics(resource);
PopulateAlternateTitles(resource);
//FetchAndLinkMovieStatistics(resource);
//PopulateAlternateTitles(resource);
return resource;
}
@@ -145,9 +150,27 @@ namespace NzbDrone.Api.Movie
return moviesResources;
}
private MovieResource GetByTitleSlug(string slug)
private Response GetByTitleSlug(dynamic options)
{
return MapToResource(_moviesService.FindByTitleSlug(slug));
var slug = "";
try
{
slug = options.slug;
// do stuff with x
}
catch (RuntimeBinderException)
{
return new NotFoundResponse();
}
try
{
return MapToResource(_moviesService.FindByTitleSlug(slug)).AsResponse(Nancy.HttpStatusCode.OK);
}
catch (ModelNotFoundException)
{
return new NotFoundResponse();
}
}
private int AddMovie(MovieResource moviesResource)

View File

@@ -21,13 +21,16 @@ namespace NzbDrone.Api.Movie
//View Only
public string Title { get; set; }
public List<AlternateTitleResource> AlternateTitles { get; set; }
public List<AlternativeTitleResource> AlternativeTitles { get; set; }
public int? SecondaryYear { get; set; }
public int SecondaryYearSourceId { 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 string PhysicalReleaseNote { get; set; }
public List<MediaCover> Images { get; set; }
public string Website { get; set; }
public bool Downloaded { get; set; }
@@ -40,6 +43,7 @@ namespace NzbDrone.Api.Movie
//View & Edit
public string Path { get; set; }
public int ProfileId { get; set; }
public MoviePathState PathState { get; set; }
//Editing Only
public bool Monitored { get; set; }
@@ -60,7 +64,7 @@ namespace NzbDrone.Api.Movie
public DateTime Added { get; set; }
public AddMovieOptions AddOptions { get; set; }
public Ratings Ratings { get; set; }
public List<string> AlternativeTitles { 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)
@@ -89,12 +93,13 @@ namespace NzbDrone.Api.Movie
if (model == null) return null;
long size = 0;
bool downloaded = false;
MovieFileResource movieFile = null;
long size = model.MovieFile?.Size ?? 0;
bool downloaded = model.MovieFile != null;
MovieFileResource movieFile = model.MovieFile?.ToResource();
if(model.MovieFile != null)
/*if(model.MovieFile != null)
{
model.MovieFile.LazyLoad();
}
@@ -104,7 +109,9 @@ namespace NzbDrone.Api.Movie
size = model.MovieFile.Value.Size;
downloaded = true;
movieFile = model.MovieFile.Value.ToResource();
}
}*/
//model.AlternativeTitles.LazyLoad();
return new MovieResource
{
@@ -115,6 +122,7 @@ namespace NzbDrone.Api.Movie
SortTitle = model.SortTitle,
InCinemas = model.InCinemas,
PhysicalRelease = model.PhysicalRelease,
PhysicalReleaseNote = model.PhysicalReleaseNote,
HasFile = model.HasFile,
Downloaded = downloaded,
//TotalEpisodeCount
@@ -128,9 +136,12 @@ namespace NzbDrone.Api.Movie
Images = model.Images,
Year = model.Year,
SecondaryYear = model.SecondaryYear,
SecondaryYearSourceId = model.SecondaryYearSourceId,
Path = model.Path,
ProfileId = model.ProfileId,
PathState = model.PathState,
Monitored = model.Monitored,
MinimumAvailability = model.MinimumAvailability,
@@ -152,7 +163,7 @@ namespace NzbDrone.Api.Movie
Tags = model.Tags,
Added = model.Added,
AddOptions = model.AddOptions,
AlternativeTitles = model.AlternativeTitles,
AlternativeTitles = model.AlternativeTitles.ToResource(),
Ratings = model.Ratings,
MovieFile = movieFile,
YouTubeTrailerId = model.YouTubeTrailerId,
@@ -174,6 +185,7 @@ namespace NzbDrone.Api.Movie
SortTitle = resource.SortTitle,
InCinemas = resource.InCinemas,
PhysicalRelease = resource.PhysicalRelease,
PhysicalReleaseNote = resource.PhysicalReleaseNote,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
@@ -184,9 +196,12 @@ namespace NzbDrone.Api.Movie
Images = resource.Images,
Year = resource.Year,
SecondaryYear = resource.SecondaryYear,
SecondaryYearSourceId = resource.SecondaryYearSourceId,
Path = resource.Path,
ProfileId = resource.ProfileId,
PathState = resource.PathState,
Monitored = resource.Monitored,
MinimumAvailability = resource.MinimumAvailability,
@@ -203,7 +218,7 @@ namespace NzbDrone.Api.Movie
Tags = resource.Tags,
Added = resource.Added,
AddOptions = resource.AddOptions,
AlternativeTitles = resource.AlternativeTitles,
//AlternativeTitles = resource.AlternativeTitles,
Ratings = resource.Ratings,
YouTubeTrailerId = resource.YouTubeTrailerId,
Studio = resource.Studio
@@ -217,6 +232,7 @@ namespace NzbDrone.Api.Movie
movie.Path = resource.Path;
movie.ProfileId = resource.ProfileId;
movie.PathState = resource.PathState;
movie.Monitored = resource.Monitored;
movie.MinimumAvailability = resource.MinimumAvailability;

View File

@@ -199,7 +199,7 @@ namespace NzbDrone.Api.Series
if (mappings == null) return;
resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
//resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
}
public void Handle(EpisodeImportedEvent message)

View File

@@ -20,7 +20,7 @@ namespace NzbDrone.Api.Series
//View Only
public string Title { get; set; }
public List<AlternateTitleResource> AlternateTitles { get; set; }
//public List<AlternativeTitleResource> AlternateTitles { get; set; }
public string SortTitle { get; set; }
public int SeasonCount

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using NzbDrone.Core.Datastore.Events;
@@ -12,7 +12,7 @@ namespace NzbDrone.Api.System.Tasks
{
private readonly ITaskManager _taskManager;
private static readonly Regex NameRegex = new Regex("(?<!^)[A-Z]", RegexOptions.Compiled);
private static readonly Regex NameRegex = new Regex("(?<!^)[A-Z][a-z]", RegexOptions.Compiled);
public TaskModule(ITaskManager taskManager, IBroadcastSignalRMessage broadcastSignalRMessage)
: base(broadcastSignalRMessage, "system/task")

View File

@@ -15,6 +15,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=sonarr&api=mySecret&eng=1")]
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
[TestCase(@"http://127.0.0.1:9117/dl/indexername?jackett_apikey=flwjiefewklfjacketmySecretsdfldskjfsdlk&path=we0re9f0sdfbase64sfdkfjsdlfjk&file=The+Torrent+File+Name.torrent")]
// NzbGet
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -108,7 +108,7 @@ namespace NzbDrone.Common.Disk
}
}
}
public bool CanUseGDIPlus()
{
try
@@ -129,7 +129,7 @@ namespace NzbDrone.Common.Disk
{
return true;
}
try
{
using (var bmp = new Bitmap(filename))
@@ -150,7 +150,7 @@ namespace NzbDrone.Common.Disk
try
{
var testPath = Path.Combine(path, "sonarr_write_test.txt");
var testPath = Path.Combine(path, "radarr_write_test.txt");
var testContent = string.Format("This file was created to verify if '{0}' is writable. It should've been automatically deleted. Feel free to delete it.", path);
File.WriteAllText(testPath, testContent);
File.Delete(testPath);
@@ -245,6 +245,25 @@ namespace NzbDrone.Common.Disk
File.Move(source, destination);
}
public void MoveFolder(string source, string destination, bool overwrite = false)
{
Ensure.That(source, () => source).IsValidPath();
Ensure.That(destination, () => destination).IsValidPath();
if (source.PathEquals(destination))
{
throw new IOException(string.Format("Source and destination can't be the same {0}", source));
}
if (FolderExists(destination) && overwrite)
{
DeleteFolder(destination, true);
}
RemoveReadOnlyFolder(source);
Directory.Move(source, destination);
}
public abstract bool TryCreateHardLink(string source, string destination);
public void DeleteFolder(string path, bool recursive)
@@ -371,6 +390,20 @@ namespace NzbDrone.Common.Disk
}
}
private static void RemoveReadOnlyFolder(string path)
{
if (Directory.Exists(path))
{
var dirInfo = new DirectoryInfo(path);
if (dirInfo.Attributes.HasFlag(FileAttributes.ReadOnly))
{
var newAttributes = dirInfo.Attributes & ~(FileAttributes.ReadOnly);
dirInfo.Attributes = newAttributes;
}
}
}
public FileAttributes GetFileAttributes(string path)
{
return File.GetAttributes(path);

View File

@@ -30,6 +30,7 @@ namespace NzbDrone.Common.Disk
void DeleteFile(string path);
void CopyFile(string source, string destination, bool overwrite = false);
void MoveFile(string source, string destination, bool overwrite = false);
void MoveFolder(string source, string destination, bool overwrite = false);
bool TryCreateHardLink(string source, string destination);
void DeleteFolder(string path, bool recursive);
string ReadAllText(string filePath);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -80,5 +80,34 @@ namespace NzbDrone.Common.Extensions
{
return source.Select(predicate).ToList();
}
public static IEnumerable<T> DropLast<T>(this IEnumerable<T> source, int n)
{
if (source == null)
throw new ArgumentNullException("source");
if (n < 0)
throw new ArgumentOutOfRangeException("n",
"Argument n should be non-negative.");
return InternalDropLast(source, n);
}
private static IEnumerable<T> InternalDropLast<T>(IEnumerable<T> source, int n)
{
Queue<T> buffer = new Queue<T>(n + 1);
foreach (T x in source)
{
buffer.Enqueue(x);
if (buffer.Count == n + 1)
yield return buffer.Dequeue();
}
}
public static bool In<T>(this T source, List<T> list)
{
return list.Contains(source);
}
}
}

View File

@@ -136,7 +136,7 @@ namespace NzbDrone.Common.Http.Dispatchers
webRequest.TransferEncoding = header.Value;
break;
case "User-Agent":
throw new NotSupportedException("User-Agent other than Sonarr not allowed.");
throw new NotSupportedException("User-Agent other than Radarr not allowed.");
case "Proxy-Connection":
throw new NotImplementedException();
default:

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Net;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
@@ -24,7 +24,7 @@ namespace NzbDrone.Common.Http
public HttpProvider(Logger logger)
{
_logger = logger;
_userAgent = string.Format("Sonarr {0}", BuildInfo.Version);
_userAgent = string.Format("Radarr {0}", BuildInfo.Version);
ServicePointManager.Expect100Continue = false;
}
@@ -58,6 +58,6 @@ namespace NzbDrone.Common.Http
}
}
}
}
}

View File

@@ -6,10 +6,10 @@ namespace NzbDrone.Common.Instrumentation
{
public class CleanseLogMessage
{
private static readonly Regex[] CleansingRules = new[]
private static readonly Regex[] CleansingRules = new[]
{
// Url
new Regex(@"(?<=\?|&)(apikey|token|passkey|auth|authkey|user|uid|api)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),

View File

@@ -63,7 +63,7 @@ namespace NzbDrone.Common.Instrumentation
{
var target = new LogentriesTarget();
target.Name = "logentriesTarget";
target.Token = "d3a83ee9-74fb-4045-ad25-a84c1d4d7c81";
target.Token = "7688c9ac-015f-45c7-bfee-73f370f5f380";
target.LogHostname = true;
target.Debug = false;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Net.Sockets;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
@@ -11,6 +11,13 @@ namespace NzbDrone.Console
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(ConsoleApp));
private enum ExitCodes : int
{
Normal = 0,
UnknownFailure = 1,
RecoverableFailure = 2
}
public static void Main(string[] args)
{
try
@@ -19,30 +26,41 @@ namespace NzbDrone.Console
NzbDroneLogger.Register(startupArgs, false, true);
Bootstrap.Start(startupArgs, new ConsoleAlerts());
}
catch (SocketException exception)
catch (SocketException e)
{
System.Console.WriteLine("");
System.Console.WriteLine("");
Logger.Fatal(exception.Message + ". This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
System.Console.WriteLine("Press enter to exit...");
System.Console.ReadLine();
Environment.Exit(1);
Logger.Fatal(e.Message + ". This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Exit(ExitCodes.RecoverableFailure);
}
catch (Exception e)
{
System.Console.WriteLine("");
System.Console.WriteLine("");
Logger.Fatal(e, "EPIC FAIL!");
System.Console.WriteLine("Press enter to exit...");
System.Console.ReadLine();
Environment.Exit(1);
Exit(ExitCodes.UnknownFailure);
}
Logger.Info("Exiting main.");
//Need this to terminate on mono (thanks nlog)
LogManager.Configuration = null;
Environment.Exit(0);
Exit(ExitCodes.Normal);
}
private static void Exit(ExitCodes exitCode)
{
LogManager.Shutdown();
if (exitCode != ExitCodes.Normal)
{
System.Console.WriteLine("Press enter to exit...");
System.Threading.Thread.Sleep(1000);
// Please note that ReadLine silently succeeds if there is no console, KeyAvailable does not.
System.Console.ReadLine();
}
Environment.Exit((int)exitCode);
}
}
}

View File

@@ -19,6 +19,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
private List<ReleaseInfo> _reports;
private RemoteMovie _remoteEpisode;
private MappingResult _mappingResult;
private Mock<IDecisionEngineSpecification> _pass1;
private Mock<IDecisionEngineSpecification> _pass2;
@@ -50,11 +51,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_reports = new List<ReleaseInfo> { new ReleaseInfo { Title = "Trolls.2016.720p.WEB-DL.DD5.1.H264-FGT" } };
_remoteEpisode = new RemoteMovie {
Movie = new Movie(),
ParsedMovieInfo = new ParsedMovieInfo()
};
_mappingResult = new MappingResult {Movie = new Movie(), MappingResultType = MappingResultType.Success};
_mappingResult.RemoteMovie = _remoteEpisode;
Mocker.GetMock<IParsingService>()
.Setup(c => c.Map(It.IsAny<ParsedMovieInfo>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>()))
.Returns(_remoteEpisode);
.Setup(c => c.Map(It.IsAny<ParsedMovieInfo>(), It.IsAny<string>(), It.IsAny<SearchCriteriaBase>())).Returns(_mappingResult);
}
private void GivenSpecifications(params Mock<IDecisionEngineSpecification>[] mocks)
@@ -121,6 +126,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
GivenSpecifications(_pass1, _pass2, _pass3);
_reports[0].Title = "Not parsable";
_mappingResult.MappingResultType = MappingResultType.NotParsable;
var results = Subject.GetRssDecision(_reports).ToList();
@@ -130,7 +136,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteMovie>(), null), Times.Never());
_pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteMovie>(), null), Times.Never());
results.Should().BeEmpty();
results.Should().NotBeEmpty();
}
[Test]
@@ -138,6 +144,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
GivenSpecifications(_pass1, _pass2, _pass3);
_reports[0].Title = "1937 - Snow White and the Seven Dwarves";
_mappingResult.MappingResultType = MappingResultType.NotParsable;
var results = Subject.GetRssDecision(_reports).ToList();
@@ -147,7 +154,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_pass2.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteMovie>(), null), Times.Never());
_pass3.Verify(c => c.IsSatisfiedBy(It.IsAny<RemoteMovie>(), null), Times.Never());
results.Should().BeEmpty();
results.Should().NotBeEmpty();
}
[Test]
@@ -156,6 +163,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenSpecifications(_pass1, _pass2, _pass3);
_remoteEpisode.Movie = null;
_mappingResult.MappingResultType = MappingResultType.TitleNotFound;
Subject.GetRssDecision(_reports);
@@ -249,12 +257,13 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenSpecifications(_pass1, _pass2, _pass3);
_remoteEpisode.Movie = null;
_mappingResult.MappingResultType = MappingResultType.TitleNotFound;
var result = Subject.GetRssDecision(_reports);
result.Should().HaveCount(1);
result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
//result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
}
[Test]
@@ -269,7 +278,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
result.Should().HaveCount(1);
result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
//result.First().RemoteMovie.DownloadAllowed.Should().BeFalse();
}
[Test]

View File

@@ -0,0 +1,111 @@
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine.Specifications.Search;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.TorrentRss;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.DecisionEngineTests.Search
{
[TestFixture]
public class TorrentSeedingSpecificationFixture : TestBase<TorrentSeedingSpecification>
{
private Series _series;
private RemoteEpisode _remoteEpisode;
private IndexerDefinition _indexerDefinition;
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateNew().With(s => s.Id = 1).Build();
_remoteEpisode = new RemoteEpisode
{
Series = _series,
Release = new TorrentInfo
{
IndexerId = 1,
Title = "Series.Title.S01.720p.BluRay.X264-RlsGrp",
Seeders = 0
}
};
_indexerDefinition = new IndexerDefinition
{
Settings = new TorrentRssIndexerSettings { MinimumSeeders = 5 }
};
Mocker.GetMock<IIndexerFactory>()
.Setup(v => v.Get(1))
.Returns(_indexerDefinition);
}
private void GivenReleaseSeeders(int? seeders)
{
(_remoteEpisode.Release as TorrentInfo).Seeders = seeders;
}
[Test]
public void should_return_true_if_not_torrent()
{
_remoteEpisode.Release = new ReleaseInfo
{
IndexerId = 1,
Title = "Series.Title.S01.720p.BluRay.X264-RlsGrp"
};
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_if_indexer_not_specified()
{
_remoteEpisode.Release.IndexerId = 0;
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_if_indexer_no_longer_exists()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(v => v.Get(It.IsAny<int>()))
.Callback<int>(i => { throw new ModelNotFoundException(typeof(IndexerDefinition), i); });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test]
public void should_return_true_if_seeds_unknown()
{
GivenReleaseSeeders(null);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[TestCase(5)]
[TestCase(6)]
public void should_return_true_if_seeds_above_or_equal_to_limit(int seeders)
{
GivenReleaseSeeders(seeders);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[TestCase(0)]
[TestCase(4)]
public void should_return_false_if_seeds_belove_limit(int seeders)
{
GivenReleaseSeeders(seeders);
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
}
}

View File

@@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteMovie));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>(), false), Times.Once());
}
[Test]
@@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteMovie));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>(), false), Times.Once());
}
[Test]
@@ -157,7 +157,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteMovie>())).Throws(new Exception());
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteMovie>(), false)).Throws(new Exception());
Subject.ProcessDecisions(decisions).Grabbed.Should().BeEmpty();
ExceptionVerification.ExpectedWarns(1);
}
@@ -183,7 +183,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteMovie));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Never());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>(), false), Times.Never());
}
[Test]

View File

@@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
Mocker.GetMock<IParsingService>()
.Setup(s => s.Map(It.IsAny<ParsedMovieInfo>(), It.IsAny<string>(), (SearchCriteriaBase)null))
.Returns(() => CreateRemoteMovie());
.Returns(() => new MappingResult{RemoteMovie = CreateRemoteMovie(), MappingResultType = MappingResultType.Success});
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.IsAny<HttpRequest>()))

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
Port = 2222,
Username = "admin",
Password = "pass",
TvCategory = "tv",
MovieCategory = "movie",
RecentTvPriority = (int)NzbgetPriority.High
};
@@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{
FileSizeLo = 1000,
RemainingSizeLo = 10,
Category = "tv",
Category = "movie",
NzbName = "Droned.1998.1080p.WEB-DL-DRONE",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }
};
@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_failed = new NzbgetHistoryItem
{
FileSizeLo = 1000,
Category = "tv",
Category = "movie",
Name = "Droned.1998.1080p.WEB-DL-DRONE",
DestDir = "somedirectory",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_completed = new NzbgetHistoryItem
{
FileSizeLo = 1000,
Category = "tv",
Category = "movie",
Name = "Droned.1998.1080p.WEB-DL-DRONE",
DestDir = "/remote/mount/tv/Droned.1998.1080p.WEB-DL-DRONE",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
@@ -81,8 +81,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
});
var configItems = new Dictionary<string, string>();
configItems.Add("Category1.Name", "tv");
configItems.Add("Category1.DestDir", @"/remote/mount/tv");
configItems.Add("Category1.Name", "movie");
configItems.Add("Category1.DestDir", @"/remote/mount/movie");
Mocker.GetMock<INzbgetProxy>()
.Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>()))
@@ -340,7 +340,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
result.IsLocalhost.Should().BeTrue();
result.OutputRootFolders.Should().NotBeNull();
result.OutputRootFolders.First().Should().Be(@"/remote/mount/tv");
result.OutputRootFolders.First().Should().Be(@"/remote/mount/movie");
}
[Test]

View File

@@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
protected void GivenRedirectToTorrent()
{
var httpHeader = new HttpHeader();
httpHeader["Location"] = "http://test.sonarr.tv/not-a-real-torrent.torrent";
httpHeader["Location"] = "http://test.radarr.video/not-a-real-torrent.torrent";
Mocker.GetMock<IHttpClient>()
.Setup(s => s.Get(It.Is<HttpRequest>(h => h.Url.FullUri == _downloadUrl)))
@@ -405,7 +405,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
[Test]
public void should_get_category_from_the_category_if_set()
{
const string category = "tv-sonarr";
const string category = "movies-radarr";
GivenMaxRatio(1.0f);
var torrent = new QBittorrentTorrent
@@ -430,7 +430,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
[Test]
public void should_get_category_from_the_label_if_the_category_is_not_available()
{
const string category = "tv-sonarr";
const string category = "movies-radarr";
GivenMaxRatio(1.0f);
var torrent = new QBittorrentTorrent

View File

@@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
ApiKey = "5c770e3197e4fe763423ee7c392c25d1",
Username = "admin",
Password = "pass",
TvCategory = "tv",
MovieCategory = "movie",
RecentTvPriority = (int)SabnzbdPriority.High
};
_queued = new SabnzbdQueue
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
Size = 1000,
Sizeleft = 10,
Timeleft = TimeSpan.FromSeconds(10),
Category = "tv",
Category = "movie",
Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE"
}
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
Status = SabnzbdDownloadStatus.Failed,
Size = 1000,
Category = "tv",
Category = "movie",
Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE"
}
@@ -81,7 +81,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
Status = SabnzbdDownloadStatus.Completed,
Size = 1000,
Category = "tv",
Category = "movie",
Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE",
Storage = "/remote/mount/vv/Droned.1998.1080p.WEB-DL-DRONE"
@@ -97,7 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
},
Categories = new List<SabnzbdCategory>
{
new SabnzbdCategory { Name = "tv", Dir = "vv" }
new SabnzbdCategory { Name = "movie", Dir = "vv" }
}
};
@@ -111,7 +111,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
_fullStatus = new SabnzbdFullStatus
{
CompleteDir = @"Y:\nzbget\root\complete".AsOsAgnostic()
CompleteDir = @"Y:\sabnzbd\root\complete".AsOsAgnostic()
};
Mocker.GetMock<ISabnzbdProxy>()
@@ -408,10 +408,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputPath.Should().Be(@"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic());
}
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed\downloads", @"vv", @"Y:\sabnzbd\root\completed\downloads", @"Y:\sabnzbd\root\completed\downloads\vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed", @"vv", @"Y:\sabnzbd\root\completed", @"Y:\sabnzbd\root\completed\vv")]
[TestCase(@"/sabnzbd/root", @"completed/downloads", @"vv", @"/sabnzbd/root/completed/downloads", @"/sabnzbd/root/completed/downloads/vv")]
[TestCase(@"/sabnzbd/root", @"completed", @"vv", @"/sabnzbd/root/completed", @"/sabnzbd/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_lt_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{
_fullStatus.CompleteDir = null;
@@ -429,10 +429,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputRootFolders.First().Should().Be(fullCategoryDir);
}
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed\downloads", @"vv", @"Y:\sabnzbd\root\completed\downloads", @"Y:\sabnzbd\root\completed\downloads\vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed", @"vv", @"Y:\sabnzbd\root\completed", @"Y:\sabnzbd\root\completed\vv")]
[TestCase(@"/sabnzbd/root", @"completed/downloads", @"vv", @"/sabnzbd/root/completed/downloads", @"/sabnzbd/root/completed/downloads/vv")]
[TestCase(@"/sabnzbd/root", @"completed", @"vv", @"/sabnzbd/root/completed", @"/sabnzbd/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_gte_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{
_fullStatus.CompleteDir = fullCompleteDir;
@@ -544,7 +544,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
public void should_test_failed_if_tv_sorting_contains_category()
{
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "tv" };
_config.Misc.tv_categories = new[] { "movie" };
var result = new NzbDroneValidationResult(Subject.Test());
@@ -554,7 +554,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
[Test]
public void should_test_failed_if_tv_sorting_default_category()
{
Subject.Definition.Settings.As<SabnzbdSettings>().TvCategory = null;
Subject.Definition.Settings.As<SabnzbdSettings>().MovieCategory = null;
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "Default" };

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