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

Compare commits

...

84 Commits

Author SHA1 Message Date
thezoggy
68d32e4d31 Fixed: Another Delete modal is fixed. (#2560)
Fixes #2537
2018-02-21 11:02:48 +01:00
thezoggy
29f540c4f2 Changed: Metadata links are now better readable. Also fixed links in the poster view. (#2562)
Fixes #2561
2018-02-21 11:02:04 +01:00
thezoggy
31eed11d1b Fixed: Messed up movie deletion modal (#2552)
Fixes #2537
2018-02-20 14:41:35 +01:00
thezoggy
ba0bbddce9 Fixed: Remove sorting on Monitor/Profile columns to prevent unexpected results until sorting can properly be handled. Quick Fix for #2540 (#2553)
Fixes #2540
2018-02-20 14:41:01 +01:00
thezoggy
a243a886f5 Fixed: OSX app has bundle name of Sonarr (#2555) 2018-02-20 14:40:35 +01:00
Leonardo Galli
033bc24984 @cosmetic update changelog 2018-02-19 16:16:04 +01:00
Leonardo Galli
e071850d4c Fixed: Alt Titles from TMDB not getting added when mappings server throws 404
Fixes #2535
2018-02-19 13:02:55 +01:00
Leonardo Galli
fa212872ab Added: Handle ctrl-c more gracefully.
Finally fixes #2218
2018-02-19 12:48:56 +01:00
Leonardo Galli
c34137c423 Merge remote-tracking branch 'origin/develop' into develop 2018-02-19 08:38:40 +01:00
Leonardo Galli
67848ebff5 Fixed: Omgwtfnbs parsing being too greedy.
Fixes #608
2018-02-19 08:37:47 +01:00
Qstick
d0406ced40 Fixed: Unable to execute custom scripts if IMDB ID is null (#2543)
fixes #1460
2018-02-19 08:19:14 +01:00
Qstick
ae88645180 Added: Device names for Join notifications (#2544)
Closes #2364
2018-02-19 08:18:36 +01:00
Qstick
8519b64947 Cleanup TV related code in API (#2530) 2018-02-19 08:18:14 +01:00
Leonardo Galli
d67d89f54a Merge remote-tracking branch 'origin/develop' into develop 2018-02-19 00:01:11 +01:00
Leonardo Galli
2b2bd16d4d Updated NLog to version 4.4.12. Should fix #2218 2018-02-19 00:00:59 +01:00
Qstick
0c23511b7a Added: Same File Size MediaFile Specification (#2532) 2018-02-18 17:29:41 +01:00
Qstick
4dc3612347 Fixed: Help icon not centered (#2531)
Fixes #2528
2018-02-18 15:06:53 +01:00
Qstick
2139246c4a Fixed: Radarr Changes every file due to timezones (#2533)
Fixes #1741
2018-02-18 15:06:26 +01:00
Leonardo Galli
c1a5e8e759 Fixed: Filters not working. Fuck you backbone. 2018-02-16 17:12:34 +01:00
Qstick
e70e76adcb Cleanup Series Code from UI (#2525) 2018-02-16 10:53:41 +01:00
Leonardo Galli
1dbb856ced Fixed: Apostrophe getting replaced by an empty string causing no search results.
Fixes #1505
2018-02-15 15:21:15 +01:00
Leonardo Galli
74396a7abb @cosmetic Updated changelog 2018-02-15 15:03:33 +01:00
Qstick
e7e9e2b154 Added: Importing extra files from downloaded movies and generate metadata such as .nfo (#2506)
Fixes #121, Fixes #167, Fixes #2262 and Fixes #1104
2018-02-15 13:39:01 +01:00
Qstick
b40423f3a3 Added: Quotes around alternative titles (#2522)
Fixes #2511
2018-02-15 11:16:59 +01:00
Qstick
b3e46d02c6 Fixed: Integration Unit Tests (#2500) 2018-02-13 19:10:49 +01:00
Qstick
081d8a8e53 Added: Backup improvements from Sonarr (#2513)
Fixes #2440
2018-02-13 19:07:26 +01:00
Leonardo Galli
2f271635f9 @cosmetic fixed build 2018-02-12 17:37:11 +01:00
Leonardo Galli
c460153e66 @cosmetic fixed indentation error. 2018-02-12 17:33:14 +01:00
Leonardo Galli
8a674181be @cosmetic Staged builds & upload artifacts. 2018-02-12 17:31:18 +01:00
Leonardo Galli
7537cef93c @cosmetic Fixed junit transformer. 2018-02-12 17:18:25 +01:00
Leonardo Galli
808b6d16e9 @cosmetic added junit transformer 2018-02-12 17:15:14 +01:00
Leonardo Galli
d1189e62c5 @cosmetic custom docker image for circleci 2018-02-12 17:10:44 +01:00
Leonardo Galli
ef86c83799 @cosmetic changed config again. 2018-02-12 16:37:33 +01:00
Leonardo Galli
aeb45e5f7e @cosmetic update test.sh 2018-02-12 16:27:48 +01:00
Leonardo Galli
149c7c534c @cosmetic update config. 2018-02-12 16:21:21 +01:00
Leonardo Galli
74ae66ba14 @cosmetic Wrong filename. 2018-02-12 16:10:53 +01:00
Leonardo Galli
f94e7b562a @cosmetic Testing CircleCI for tests. 2018-02-12 16:06:31 +01:00
Leonardo Galli
f5a7a2f29a @cosmetic 2018-02-11 22:59:11 +01:00
Qstick
1514a00b8f Updated: NzbDrone references in FirewallAdapter.cs (#2504) 2018-02-11 17:22:31 +01:00
Scott
3ed0652feb Fixed: XSS vulnerability in the navbar search. (#2505)
Fixes #2503
2018-02-11 17:20:55 +01:00
Qstick
f4e2a510f2 Fixed: StartNzbDroneService.cs unit test (#2499) 2018-02-10 00:04:22 +01:00
geogolem
8edd15b5f8 Merge pull request #2497 from geogolem/selectAllMovieEditor
selectAll and deselectAll MovieEditor buttons
2018-02-09 11:59:31 -05:00
geogolem
2fdfd0fba5 selectAll and deselectAll MovieEditor buttons 2018-02-09 11:41:31 -05:00
geogolem
8b201af053 Merge pull request #2493 from geogolem/develop
fix build problem on windows
2018-02-08 09:35:41 -05:00
geogolem
976bc1a6a5 fix build problem on windows 2018-02-08 09:22:58 -05:00
Leonardo Galli
16ba7194a9 Merge branch 'develop' of https://github.com/Radarr/Radarr into develop 2018-02-08 11:26:58 +01:00
Leonardo Galli
a151fbbcbe Revert "Fixed: Removed hebrew ISO, since english movies are still in english. (#1922)" 2018-02-08 11:26:43 +01:00
Leonardo Galli
71db67af2c @cosmetic 2018-02-07 17:27:04 +01:00
Leonardo Galli
1d2231a96d @cosmetic 2018-02-07 17:26:43 +01:00
Leonardo Galli
0837d3a8a0 @cosmetic 2018-02-07 17:26:23 +01:00
Leonardo Galli
05e5d610a3 @cosmetic 2018-02-07 17:11:51 +01:00
Leonardo Galli
d2f99f1330 Fixed: Error with deluge when it doesn’t report a Hash.
Fixes #2329
2018-02-07 15:59:14 +01:00
Leonardo Galli
27001b48f6 Fixed: Logging error when accessing mount point
Fixes #2305
2018-02-07 15:26:25 +01:00
Leonardo Galli
97ab4cbcbd Fixed: Invalid runtime from CP causing issues importing.
Fixes #2081
2018-02-07 12:04:27 +01:00
Leonardo Galli
8b3a71a537 Fixed: Typo in TMDB Settings.
Fixes #2077
2018-02-07 11:57:49 +01:00
Leonardo Galli
e22141e2ed Fixed: Hopefully fixed errors with Delay Profiles.
Fixes #1817
2018-02-07 11:24:58 +01:00
Leonardo Galli
11211dc2ed Fixed: Error when importing files and old folder doesn’t exist.
Fixes #2485
2018-02-07 11:08:05 +01:00
Leonardo Galli
e71e518d30 Fixed: Zooqle torrents not getting added, since their torrent file is messed up.
Fixes #1516
2018-02-07 00:10:33 +01:00
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
424 changed files with 7235 additions and 10813 deletions

5
.circleci/Dockerfile Normal file
View File

@@ -0,0 +1,5 @@
FROM mono:4.8
RUN apt-get update && apt-get install -y git ssh tar gzip ca-certificates
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -E -
RUN apt-get install -y nodejs npm

40
.circleci/config.yml Normal file
View File

@@ -0,0 +1,40 @@
version: 2
jobs:
build:
docker:
- image: gallileo/radarr-cci-primary:4.8
steps:
- checkout
- run: git submodule update --init --recursive
- run:
name: Clean Build
command: ./build.sh Clean
- run:
name: Restore Nuget
command: ./build.sh NugetMono
- run:
name: Build
command: ./build.sh Build
- run:
name: Gulp
command: ./build.sh Gulp
- run:
name: Package
command: ./build.sh Package
- run:
name: Preparing Tests
command: mkdir _tests/reports
- run:
name: Testing
command: ./test.sh Linux Unit
- store_test_results:
path: _tests/reports/
- store_artifacts:
path: _output
- store_artifacts:
path: _output_mono
- store_artifacts:
path: _output_osx
- store_artifacts:
path: _output_osx_app

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/test-run">
<testsuites tests="{@testcasecount}" failures="{@failed}" disabled="{@skipped}" time="{@duration}">
<xsl:apply-templates/>
</testsuites>
</xsl:template>
<xsl:template match="test-suite">
<xsl:if test="test-case">
<testsuite tests="{@testcasecount}" time="{@duration}" errors="{@testcasecount - @passed - @skipped - @failed}" failures="{@failed}" skipped="{@skipped}" timestamp="{@start-time}">
<xsl:attribute name="name">
<xsl:for-each select="ancestor-or-self::test-suite/@name">
<xsl:value-of select="concat(., '.')"/>
</xsl:for-each>
</xsl:attribute>
<xsl:apply-templates select="test-case"/>
</testsuite>
<xsl:apply-templates select="test-suite"/>
</xsl:if>
<xsl:if test="not(test-case)">
<xsl:apply-templates/>
</xsl:if>
</xsl:template>
<xsl:template match="test-case">
<testcase name="{@name}" assertions="{@asserts}" time="{@duration}" status="{@result}" classname="{@classname}">
<xsl:if test="@runstate = 'Skipped' or @runstate = 'Ignored'">
<skipped/>
</xsl:if>
<xsl:apply-templates/>
</testcase>
</xsl:template>
<xsl:template match="command-line"/>
<xsl:template match="settings"/>
<xsl:template match="output">
<system-out>
<xsl:value-of select="."/>
</system-out>
</xsl:template>
<xsl:template match="stack-trace">
</xsl:template>
<xsl:template match="test-case/failure">
<failure message="{./message}">
<xsl:value-of select="./stack-trace"/>
</failure>
</xsl:template>
<xsl:template match="test-suite/failure"/>
<xsl:template match="test-case/reason">
<skipped message="{./message}"/>
</xsl:template>
<xsl:template match="test-case/assertions">
</xsl:template>
<xsl:template match="test-suite/reason"/>
<xsl:template match="properties"/>
</xsl:stylesheet>

View File

@@ -4,13 +4,17 @@ Check first that your problem is not listed in our wiki section:
* https://github.com/Radarr/Radarr/wiki/Common-Problems
* https://github.com/Radarr/Radarr/wiki/FAQ
**Just because you receive an exception in your logs, doesn't mean it's a bug and should be reported here. Often it's something else, such as a permission error. If you are unsure ask on the Discord or Subreddit first.**
Visit our [Discord server](https://discord.gg/NWYch8M) or [Subreddit](https://reddit.com/r/radarr) for support or longer discussions. Support questions posed on here will be closed immediately.
Provide a description of the feature request or bug here, the more details the better.
Please also try to include the following if you are reporting a bug
Please also include the following if you are reporting a bug. If you do not include it, the issue will probably be closed as we cannot help you.
**Radarr Version:**
**Logs:**
**Mono Version:**
**Debug Logs:**
Please use the search bar and make sure you are not submitting an already submitted issue.
Visit our [Discord server](https://discord.gg/NWYch8M) for support or longer discussions.

View File

@@ -1,5 +1,117 @@
# Changelog
## (unreleased)
### **New features**
- Handle ctrl-c more gracefully. [Leonardo Galli]
- Device names for Join notifications (#2544) [Qstick]
- Same File Size MediaFile Specification (#2532) [Qstick]
- Updated NLog to version 4.4.12. Should fix #2218. [Leonardo Galli]
- Importing extra files from downloaded movies and generate metadata such as .nfo (#2506) [Qstick]
- Quotes around alternative titles (#2522) [Qstick]
- Backup improvements from Sonarr (#2513) [Qstick]
- NzbDrone references in FirewallAdapter.cs (#2504) [Qstick]
### **Fixes**
- Alt Titles from TMDB not getting added when mappings server throws 404. [Leonardo Galli]
- Unable to execute custom scripts if IMDB ID is null (#2543) [Qstick]
- Cleanup TV related code in API (#2530) [Qstick]
- Omgwtfnbs parsing being too greedy. [Leonardo Galli]
- Help icon not centered (#2531) [Qstick]
- Radarr Changes every file due to timezones (#2533) [Qstick]
- Filters not working. Fuck you backbone. [Leonardo Galli]
- Cleanup Series Code from UI (#2525) [Qstick]
- Apostrophe getting replaced by an empty string causing no search results. [Leonardo Galli]
- Integration Unit Tests (#2500) [Qstick]
- XSS vulnerability in the navbar search. (#2505) [Scott]
- StartNzbDroneService.cs unit test (#2499) [Qstick]
- SelectAll and deselectAll MovieEditor buttons. [geogolem]
- Fix build problem on windows. [geogolem]
- Revert "Fixed: Removed hebrew ISO, since english movies are still in english. (#1922)" [Leonardo Galli]
- Error with deluge when it doesnt report a Hash. [Leonardo Galli]
- Logging error when accessing mount point. [Leonardo Galli]
- Invalid runtime from CP causing issues importing. [Leonardo Galli]
- Typo in TMDB Settings. [Leonardo Galli]
- Hopefully fixed errors with Delay Profiles. [Leonardo Galli]
- Error when importing files and old folder doesnt exist. [Leonardo Galli]
- Zooqle torrents not getting added, since their torrent file is messed up. [Leonardo Galli]
## v0.2.0.935 (2018-02-06)
### **New features**
- Include total space with root folders. [Leonardo Galli]
- Manual Import now adds year after movie title for filtering. This should help finding movies such as IT. [Leonardo Galli]
- Option to require indexer flags per indexer. (e.g. only download freeleech torrents from a private tracker) (#2460) [Leonardo Galli]
- Files downloaded with different quality than grabbed will get rejected. [Leonardo Galli]
- TMDbSettings.cs to allow pipe for or for genre ids (#2389) [crhammock]
- Dynamic paths cleanup old folders now! [Leonardo Galli]
### **Fixes**
- No Physical Release Date causing exception when setting last write time. [Leonardo Galli]
- Movies not getting unmonitored when folder gets deleted. [Leonardo Galli]
- Rare case of null quality causing issues with manual import. [Leonardo Galli]
- Manual Import not automatically choosing right movie. [Leonardo Galli]
- Rare case of RequiredIndexerFlags failing with old Newznab indexers. [Leonardo Galli]
- Folder name getting messed up when adding movies via a list. [Leonardo Galli]
- Error when adding an already excluded movie to the exclusion list. [Leonardo Galli]
- Last commit still not compiling (whoops squared) [Leonardo Galli]
- Last commit not compiling (whoops) [Leonardo Galli]
- Clean Library being to agressive when lists are having failures. [Leonardo Galli]
- Error when nno quality was associated with a movie file. [Leonardo Galli]
- Allowing in use Profiles to be Deleted. [Leonardo Galli]
- Error when Movie has no imdbid when searching Rargb. [Leonardo Galli]
- Rargb failing when imdbid is not found. [Leonardo Galli]
- {Original Filename} not allowed in Movie Filename. [Leonardo Galli]
- Look for changes to package.json before using old build cache (#2445) [Qstick]
- HistoryDetailsLayoutTemplate.hbs (#2361) [Pieter Janssens]
## v0.2.0.910 (2017-12-13)
### **New features**
- Separate naming tags for AudioLanguage and SubtitleLanguage (#2261) (Fixes #2257) [fhscholl]
- Include APFS disks in disk space calculation. [Leonardo Galli]
- Upgrade MediaInfo to 17.10 (Windows/macOS) [Leonardo Galli]
- Support for VF2 french tag. (#2291) (Fixes #2290) [kriegalex]
- Customize Slack Channel (#2308) (Fixes #2298) [grokdesigns]
- SceneName to MovieFile API output (#2250) (Fixes #2245) [fhscholl]
- Functionality to XBMC and Plex to update indivdual titles. Also: Notification Cleanup (#2240) [fhscholl]
- FolderPath to the Movie Webhook (#2230) [adnanklink]
- Download_Id to On Download/On Upgrade (#2229) [adnanklink]
- Movie_Quality to onGrab (#2221) (Fixes #1833) [fhscholl]
- Webhook Improvements (#2220) (Fixes #1751) [fhscholl]
- Message about adblockers preventing the log table from loading (#2213) (Fixes #2209) [James White]
- Sabnzbd Update test cases and rename to MovieCategory (#2212) [James White]
- Nzbget Rename TvCategory references to MovieCategory (#2211) [James White]
- Change default port of qBittorrent download client config (#2187) [James White]
- Initial state for torrents added to qBittorrent (#2176) [James White]
- Adjust ambiguous date options (#2165) [James White]
- A default name for Radarr.ics (#2163) [James White]
### **Fixes**
- Fixed MediaCover endpoint. [Taloth Saldono]
- Don't handle content requests in IndexHtmlMapper. [Mark McDowall]
- Movies parsed from lists with no year and only title getting added mutliple times. [Leonardo Galli]
- Security Vulnerabilities allowing authentication to be bypassed (discovered by Kyle Neideck) [Taloth Saldono]
- Movie Editor Path screwed up. Might also fix some other movie editor issues. (Fixes #2170) [Leonardo Galli]
- Tags disappearing (Fixes #2204) [Leonardo Galli]
- Moment.js deprecated zone and add functions (Fixes #2232) (Fixes #2231) (#2264) [Fish2]
- CPU locking at a 100% in certain instances. (#2258) (Fixes #2218) [Mike]
- Revert "Fixed: moment.js deprecated zone and Added: and lossless compression of images (#2232) (Fixes #2231)" [Fish2]
- Moment.js deprecated zone and Added: and lossless compression of images (#2232) (Fixes #2231) [Fish2]
- Fixes #2218. (#2254) [Mike]
- Minor error message tweak (#1778) [Oliver Rivett-Carnac]
- UTorrent initial state feature (#2192) [James White]
- Add IsUpgrade and related deleted file paths for CustomScript (#2205) [fhscholl]
- Typo on margin-bottom (#2182) [James White]
- Manual Import. Fixes #2160. [Leonardo Galli]
- Remove unit on zero values (#2178) [James White]
- Jackett apikey cleaned from log again. (#2177) [James White]
- Manual Movie Page Filtering. [Leonardo Galli]
- MediaInfo not getting read when quality isn't Bluray, Web-dl or HDTV. Fixes #1465. Fixes #1572. [Leonardo Galli]
## v0.2.0.870 (2017-10-09)
### **New features**

View File

@@ -85,7 +85,7 @@ Radarr is currently undergoing rapid development and pull requests are actively
### Planned Features
* Downloading Metadata such as trailers or subtitles (\*)
* Importing Metadata such as trailers or subtitles (\*)
* Adding metadata such as posters and information for Kodi and others to use (\*)
* Dynamically renaming folders with quality info, etc. (\*)
* Supporting custom folder structures, such as all movie files in one folder (\*)

View File

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

@@ -69,11 +69,21 @@ BuildWithMSBuild()
CheckExitCode MSBuild.exe $slnFile //p:Configuration=Release //p:Platform=x86 //t:Build //m //p:AllowedReferenceRelatedFileExtensions=.pdb
}
BuildWithXbuild()
RestoreNuget()
{
export MONO_IOMAP=case
mono $nuget restore $slnFile
}
CleanWithXbuild()
{
export MONO_IOMAP=case
CheckExitCode xbuild /t:Clean $slnFile
mono $nuget restore $slnFile
}
BuildWithXbuild()
{
export MONO_IOMAP=case
CheckExitCode xbuild /p:Configuration=Release /p:Platform=x86 /t:Build /p:AllowedReferenceRelatedFileExtensions=.pdb $slnFile
}
@@ -86,6 +96,8 @@ Build()
if [ $runtime = "dotnet" ] ; then
BuildWithMSBuild
else
CleanWithXbuild
RestoreNuget
BuildWithXbuild
fi
@@ -256,10 +268,42 @@ case "$(uname -s)" in
;;
esac
Build
RunGulp
PackageMono
PackageOsx
PackageOsxApp
PackageTests
CleanupWindowsPackage
if [ $# -eq 0 ]
then
Build
RunGulp
PackageMono
PackageOsx
PackageOsxApp
PackageTests
CleanupWindowsPackage
fi
if [ "$1" = "CleanXbuild" ]
then rm -rf $outputFolder
CleanWithXbuild
fi
if [ "$1" = "NugetMono" ]
then rm -rf $outputFolder
RestoreNuget
fi
if [ "$1" = "Build" ]
then BuildWithXbuild
CleanFolder $outputFolder false
AddJsonNet
rm $outputFolder/Mono.Posix.dll
fi
if [ "$1" = "Gulp" ]
then RunGulp
fi
if [ "$1" = "Package" ]
then PackageMono
PackageOsx
PackageOsxApp
PackageTests
CleanupWindowsPackage
fi

View File

@@ -19,7 +19,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Sonarr</string>
<string>Radarr</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>

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

@@ -51,9 +51,8 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

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

View File

@@ -96,7 +96,7 @@ namespace MonoTorrent.BEncoding
if (stream == null)
throw new ArgumentNullException("stream");
return Decode(new RawReader(stream));
return Decode(new RawReader(stream, false));
}

View File

@@ -1,9 +1,8 @@
using System;
using System;
using System.Collections.Generic;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
using NzbDrone.Core.Indexers;
namespace NzbDrone.Api.Blacklist
@@ -20,7 +19,6 @@ namespace NzbDrone.Api.Blacklist
public string Indexer { get; set; }
public string Message { get; set; }
public MovieResource Movie { get; set; }
public SeriesResource Series { get; set; }
}
public static class BlacklistResourceMapper
@@ -41,8 +39,7 @@ namespace NzbDrone.Api.Blacklist
Protocol = model.Protocol,
Indexer = model.Indexer,
Message = model.Message,
Movie = model.Movie.ToResource(),
Series = model.Series.ToResource()
Movie = model.Movie.ToResource()
};
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Series;
using NzbDrone.Api.Movies;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
@@ -17,7 +15,6 @@ using NzbDrone.Core.Validation.Paths;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Validation;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Calendar

View File

@@ -41,6 +41,16 @@ 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;
@@ -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
{

View File

@@ -1,4 +1,4 @@
using NzbDrone.Api.REST;
using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.MediaFiles;
@@ -22,6 +22,7 @@ namespace NzbDrone.Api.Config
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
public bool CopyUsingHardlinks { get; set; }
public bool ImportExtraFiles { get; set; }
public string ExtraFileExtensions { get; set; }
public bool EnableMediaInfo { get; set; }
}
@@ -48,6 +49,7 @@ namespace NzbDrone.Api.Config
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
CopyUsingHardlinks = model.CopyUsingHardlinks,
ImportExtraFiles = model.ImportExtraFiles,
ExtraFileExtensions = model.ExtraFileExtensions,
EnableMediaInfo = model.EnableMediaInfo
};

View File

@@ -1,88 +0,0 @@
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Api.REST;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR;
namespace NzbDrone.Api.EpisodeFiles
{
public class EpisodeFileModule : NzbDroneRestModuleWithSignalR<EpisodeFileResource, EpisodeFile>,
IHandle<EpisodeFileAddedEvent>
{
private readonly IMediaFileService _mediaFileService;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly ISeriesService _seriesService;
private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly Logger _logger;
public EpisodeFileModule(IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService,
IRecycleBinProvider recycleBinProvider,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
Logger logger)
: base(signalRBroadcaster)
{
_mediaFileService = mediaFileService;
_recycleBinProvider = recycleBinProvider;
_seriesService = seriesService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
_logger = logger;
GetResourceById = GetEpisodeFile;
GetResourceAll = GetEpisodeFiles;
UpdateResource = SetQuality;
DeleteResource = DeleteEpisodeFile;
}
private EpisodeFileResource GetEpisodeFile(int id)
{
var episodeFile = _mediaFileService.Get(id);
var series = _seriesService.GetSeries(episodeFile.SeriesId);
return episodeFile.ToResource(series, _qualityUpgradableSpecification);
}
private List<EpisodeFileResource> GetEpisodeFiles()
{
if (!Request.Query.SeriesId.HasValue)
{
throw new BadRequestException("seriesId is missing");
}
var seriesId = (int)Request.Query.SeriesId;
var series = _seriesService.GetSeries(seriesId);
return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
}
private void SetQuality(EpisodeFileResource episodeFileResource)
{
var episodeFile = _mediaFileService.Get(episodeFileResource.Id);
episodeFile.Quality = episodeFileResource.Quality;
_mediaFileService.Update(episodeFile);
}
private void DeleteEpisodeFile(int id)
{
var episodeFile = _mediaFileService.Get(id);
var series = _seriesService.GetSeries(episodeFile.SeriesId);
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
_logger.Info("Deleting episode file: {0}", fullPath);
_recycleBinProvider.DeleteFile(fullPath);
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
}
public void Handle(EpisodeFileAddedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.Id);
}
}
}

View File

@@ -1,64 +0,0 @@
using System;
using System.IO;
using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Api.EpisodeFiles
{
public class EpisodeFileResource : RestResource
{
public int SeriesId { get; set; }
public int SeasonNumber { get; set; }
public string RelativePath { get; set; }
public string Path { get; set; }
public long Size { get; set; }
public DateTime DateAdded { get; set; }
public string SceneName { get; set; }
public QualityModel Quality { get; set; }
public bool QualityCutoffNotMet { get; set; }
}
public static class EpisodeFileResourceMapper
{
private static EpisodeFileResource ToResource(this Core.MediaFiles.EpisodeFile model)
{
if (model == null) return null;
return new EpisodeFileResource
{
Id = model.Id,
SeriesId = model.SeriesId,
SeasonNumber = model.SeasonNumber,
RelativePath = model.RelativePath,
//Path
Size = model.Size,
DateAdded = model.DateAdded,
SceneName = model.SceneName,
Quality = model.Quality,
//QualityCutoffNotMet
};
}
public static EpisodeFileResource ToResource(this Core.MediaFiles.EpisodeFile model, Core.Tv.Series series, Core.DecisionEngine.IQualityUpgradableSpecification qualityUpgradableSpecification)
{
if (model == null) return null;
return new EpisodeFileResource
{
Id = model.Id,
SeriesId = model.SeriesId,
SeasonNumber = model.SeasonNumber,
RelativePath = model.RelativePath,
Path = Path.Combine(series.Path, model.RelativePath),
Size = model.Size,
DateAdded = model.DateAdded,
SceneName = model.SceneName,
Quality = model.Quality,
QualityCutoffNotMet = qualityUpgradableSpecification.CutoffNotMet(series.Profile.Value, model.Quality)
};
}
}
}

View File

@@ -1,41 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR;
using Nancy;
namespace NzbDrone.Api.Episodes
{
public class EpisodeModule : EpisodeModuleWithSignalR
{
public EpisodeModule(ISeriesService seriesService,
IEpisodeService episodeService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster)
{
GetResourceAll = GetEpisodes;
UpdateResource = SetMonitored;
}
private List<EpisodeResource> GetEpisodes()
{
if (!Request.Query.SeriesId.HasValue)
{
throw new BadRequestException("seriesId is missing");
}
var seriesId = (int)Request.Query.SeriesId;
var resources = MapToResource(_episodeService.GetEpisodeBySeries(seriesId), false, true);
return resources;
}
private void SetMonitored(EpisodeResource episodeResource)
{
_episodeService.SetEpisodeMonitored(episodeResource.Id, episodeResource.Monitored);
}
}
}

View File

@@ -1,126 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Common.Extensions;
using NzbDrone.Api.EpisodeFiles;
using NzbDrone.Api.Series;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Episodes
{
public abstract class EpisodeModuleWithSignalR : NzbDroneRestModuleWithSignalR<EpisodeResource, Episode>,
IHandle<EpisodeGrabbedEvent>,
IHandle<EpisodeDownloadedEvent>
{
protected readonly IEpisodeService _episodeService;
protected readonly ISeriesService _seriesService;
protected readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
protected EpisodeModuleWithSignalR(IEpisodeService episodeService,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(signalRBroadcaster)
{
_episodeService = episodeService;
_seriesService = seriesService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetEpisode;
}
protected EpisodeModuleWithSignalR(IEpisodeService episodeService,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster,
string resource)
: base(signalRBroadcaster, resource)
{
_episodeService = episodeService;
_seriesService = seriesService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
GetResourceById = GetEpisode;
}
protected EpisodeResource GetEpisode(int id)
{
var episode = _episodeService.GetEpisode(id);
var resource = MapToResource(episode, true, true);
return resource;
}
protected EpisodeResource MapToResource(Episode episode, bool includeSeries, bool includeEpisodeFile)
{
var resource = episode.ToResource();
if (includeSeries || includeEpisodeFile)
{
var series = episode.Series ?? _seriesService.GetSeries(episode.SeriesId);
if (includeSeries)
{
resource.Series = series.ToResource();
}
if (includeEpisodeFile && episode.EpisodeFileId != 0)
{
resource.EpisodeFile = episode.EpisodeFile.Value.ToResource(series, _qualityUpgradableSpecification);
}
}
return resource;
}
protected List<EpisodeResource> MapToResource(List<Episode> episodes, bool includeSeries, bool includeEpisodeFile)
{
var result = episodes.ToResource();
if (includeSeries || includeEpisodeFile)
{
var seriesDict = new Dictionary<int, Core.Tv.Series>();
for (var i = 0; i < episodes.Count; i++)
{
var episode = episodes[i];
var resource = result[i];
var series = episode.Series ?? seriesDict.GetValueOrDefault(episodes[i].SeriesId) ?? _seriesService.GetSeries(episodes[i].SeriesId);
seriesDict[series.Id] = series;
if (includeSeries)
{
resource.Series = series.ToResource();
}
if (includeEpisodeFile && episodes[i].EpisodeFileId != 0)
{
resource.EpisodeFile = episodes[i].EpisodeFile.Value.ToResource(series, _qualityUpgradableSpecification);
}
}
}
return result;
}
public void Handle(EpisodeGrabbedEvent message)
{
foreach (var episode in message.Episode.Episodes)
{
var resource = episode.ToResource();
resource.Grabbed = true;
BroadcastResourceChange(ModelAction.Updated, resource);
}
}
public void Handle(EpisodeDownloadedEvent message)
{
foreach (var episode in message.Episode.Episodes)
{
BroadcastResourceChange(ModelAction.Updated, episode.Id);
}
}
}
}

View File

@@ -1,78 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using NzbDrone.Api.EpisodeFiles;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Episodes
{
public class EpisodeResource : RestResource
{
public int SeriesId { get; set; }
public int EpisodeFileId { get; set; }
public int SeasonNumber { get; set; }
public int EpisodeNumber { get; set; }
public string Title { get; set; }
public string AirDate { get; set; }
public DateTime? AirDateUtc { get; set; }
public string Overview { get; set; }
public EpisodeFileResource EpisodeFile { get; set; }
public bool HasFile { get; set; }
public bool Monitored { get; set; }
public int? AbsoluteEpisodeNumber { get; set; }
public int? SceneAbsoluteEpisodeNumber { get; set; }
public int? SceneEpisodeNumber { get; set; }
public int? SceneSeasonNumber { get; set; }
public bool UnverifiedSceneNumbering { get; set; }
public string SeriesTitle { get; set; }
public SeriesResource Series { get; set; }
//Hiding this so people don't think its usable (only used to set the initial state)
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public bool Grabbed { get; set; }
}
public static class EpisodeResourceMapper
{
public static EpisodeResource ToResource(this Episode model)
{
if (model == null) return null;
return new EpisodeResource
{
Id = model.Id,
SeriesId = model.SeriesId,
EpisodeFileId = model.EpisodeFileId,
SeasonNumber = model.SeasonNumber,
EpisodeNumber = model.EpisodeNumber,
Title = model.Title,
AirDate = model.AirDate,
AirDateUtc = model.AirDateUtc,
Overview = model.Overview,
//EpisodeFile
HasFile = model.HasFile,
Monitored = model.Monitored,
AbsoluteEpisodeNumber = model.AbsoluteEpisodeNumber,
SceneAbsoluteEpisodeNumber = model.SceneAbsoluteEpisodeNumber,
SceneEpisodeNumber = model.SceneEpisodeNumber,
SceneSeasonNumber = model.SceneSeasonNumber,
UnverifiedSceneNumbering = model.UnverifiedSceneNumbering,
SeriesTitle = model.SeriesTitle,
//Series = model.Series.MapToResource(),
};
}
public static List<EpisodeResource> ToResource(this IEnumerable<Episode> models)
{
if (models == null) return null;
return models.Select(ToResource).ToList();
}
}
}

View File

@@ -1,37 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Api.Episodes
{
public class RenameEpisodeModule : NzbDroneRestModule<RenameEpisodeResource>
{
private readonly IRenameEpisodeFileService _renameEpisodeFileService;
public RenameEpisodeModule(IRenameEpisodeFileService renameEpisodeFileService)
: base("rename")
{
_renameEpisodeFileService = renameEpisodeFileService;
GetResourceAll = GetEpisodes;
}
private List<RenameEpisodeResource> GetEpisodes()
{
if (!Request.Query.SeriesId.HasValue)
{
throw new BadRequestException("seriesId is missing");
}
var seriesId = (int)Request.Query.SeriesId;
if (Request.Query.SeasonNumber.HasValue)
{
var seasonNumber = (int)Request.Query.SeasonNumber;
return _renameEpisodeFileService.GetRenamePreviews(seriesId, seasonNumber).ToResource();
}
return _renameEpisodeFileService.GetRenamePreviews(seriesId).ToResource();
}
}
}

View File

@@ -1,39 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Episodes
{
public class RenameEpisodeResource : RestResource
{
public int SeriesId { get; set; }
public int SeasonNumber { get; set; }
public List<int> EpisodeNumbers { get; set; }
public int EpisodeFileId { get; set; }
public string ExistingPath { get; set; }
public string NewPath { get; set; }
}
public static class RenameEpisodeResourceMapper
{
public static RenameEpisodeResource ToResource(this Core.MediaFiles.RenameEpisodeFilePreview model)
{
if (model == null) return null;
return new RenameEpisodeResource
{
SeriesId = model.SeriesId,
SeasonNumber = model.SeasonNumber,
EpisodeNumbers = model.EpisodeNumbers.ToList(),
EpisodeFileId = model.EpisodeFileId,
ExistingPath = model.ExistingPath,
NewPath = model.NewPath
};
}
public static List<RenameEpisodeResource> ToResource(this IEnumerable<Core.MediaFiles.RenameEpisodeFilePreview> models)
{
return models.Select(ToResource).ToList();
}
}
}

View File

@@ -0,0 +1,45 @@
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.Extras.Files;
using NzbDrone.Core.Extras.Metadata.Files;
using NzbDrone.Core.Extras.Others;
using NzbDrone.Core.Extras.Subtitles;
namespace NzbDrone.Api.ExtraFiles
{
public class ExtraFileModule : NzbDroneRestModule<ExtraFileResource>
{
private readonly IExtraFileService<SubtitleFile> _subtitleFileService;
private readonly IExtraFileService<MetadataFile> _metadataFileService;
private readonly IExtraFileService<OtherExtraFile> _otherFileService;
public ExtraFileModule(IExtraFileService<SubtitleFile> subtitleFileService, IExtraFileService<MetadataFile> metadataFileService, IExtraFileService<OtherExtraFile> otherExtraFileService)
: base("/extrafile")
{
_subtitleFileService = subtitleFileService;
_metadataFileService = metadataFileService;
_otherFileService = otherExtraFileService;
GetResourceAll = GetFiles;
}
private List<ExtraFileResource> GetFiles()
{
if (!Request.Query.MovieId.HasValue)
{
throw new BadRequestException("MovieId is missing");
}
var extraFiles = new List<ExtraFileResource>();
List<SubtitleFile> subtitleFiles = _subtitleFileService.GetFilesByMovie(Request.Query.MovieId);
List<MetadataFile> metadataFiles = _metadataFileService.GetFilesByMovie(Request.Query.MovieId);
List<OtherExtraFile> otherExtraFiles = _otherFileService.GetFilesByMovie(Request.Query.MovieId);
extraFiles.AddRange(subtitleFiles.ToResource());
extraFiles.AddRange(metadataFiles.ToResource());
extraFiles.AddRange(otherExtraFiles.ToResource());
return extraFiles;
}
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.Extras.Files;
using NzbDrone.Core.Extras.Metadata.Files;
using NzbDrone.Core.Extras.Others;
using NzbDrone.Core.Extras.Subtitles;
namespace NzbDrone.Api.ExtraFiles
{
public class ExtraFileResource : RestResource
{
public int MovieId { get; set; }
public int? MovieFileId { get; set; }
public string RelativePath { get; set; }
public string Extension { get; set; }
public ExtraFileType Type { get; set; }
}
public static class ExtraFileResourceMapper
{
public static ExtraFileResource ToResource(this MetadataFile model)
{
if (model == null) return null;
return new ExtraFileResource
{
Id = model.Id,
MovieId = model.MovieId,
MovieFileId = model.MovieFileId,
RelativePath = model.RelativePath,
Extension = model.Extension,
Type = ExtraFileType.Metadata
};
}
public static ExtraFileResource ToResource(this SubtitleFile model)
{
if (model == null) return null;
return new ExtraFileResource
{
Id = model.Id,
MovieId = model.MovieId,
MovieFileId = model.MovieFileId,
RelativePath = model.RelativePath,
Extension = model.Extension,
Type = ExtraFileType.Subtitle
};
}
public static ExtraFileResource ToResource(this OtherExtraFile model)
{
if (model == null) return null;
return new ExtraFileResource
{
Id = model.Id,
MovieId = model.MovieId,
MovieFileId = model.MovieFileId,
RelativePath = model.RelativePath,
Extension = model.Extension,
Type = ExtraFileType.Other
};
}
public static List<ExtraFileResource> ToResource(this IEnumerable<SubtitleFile> movies)
{
return movies.Select(ToResource).ToList();
}
public static List<ExtraFileResource> ToResource(this IEnumerable<MetadataFile> movies)
{
return movies.Select(ToResource).ToList();
}
public static List<ExtraFileResource> ToResource(this IEnumerable<OtherExtraFile> movies)
{
return movies.Select(ToResource).ToList();
}
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;

View File

@@ -1,9 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.History;
using NzbDrone.Core.Qualities;
@@ -12,9 +10,7 @@ namespace NzbDrone.Api.History
{
public class HistoryResource : RestResource
{
public int EpisodeId { get; set; }
public int MovieId { get; set; }
public int SeriesId { get; set; }
public string SourceTitle { get; set; }
public QualityModel Quality { get; set; }
public bool QualityCutoffNotMet { get; set; }
@@ -25,8 +21,6 @@ namespace NzbDrone.Api.History
public Dictionary<string, string> Data { get; set; }
public MovieResource Movie { get; set; }
public EpisodeResource Episode { get; set; }
public SeriesResource Series { get; set; }
}
public static class HistoryResourceMapper
@@ -38,9 +32,6 @@ namespace NzbDrone.Api.History
return new HistoryResource
{
Id = model.Id,
EpisodeId = model.EpisodeId,
SeriesId = model.SeriesId,
MovieId = model.MovieId,
SourceTitle = model.SourceTitle,
Quality = model.Quality,
@@ -51,8 +42,6 @@ namespace NzbDrone.Api.History
EventType = model.EventType,
Data = model.Data
//Episode
//Series
};
}
}

View File

@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movies;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Common.Crypto;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Qualities;
@@ -15,9 +14,7 @@ namespace NzbDrone.Api.ManualImport
public string RelativePath { get; set; }
public string Name { get; set; }
public long Size { get; set; }
public SeriesResource Series { get; set; }
public int? SeasonNumber { get; set; }
public List<EpisodeResource> Episodes { get; set; }
public MovieResource Movie { get; set; }
public QualityModel Quality { get; set; }
public int QualityWeight { get; set; }
public string DownloadId { get; set; }
@@ -38,9 +35,7 @@ namespace NzbDrone.Api.ManualImport
RelativePath = model.RelativePath,
Name = model.Name,
Size = model.Size,
Series = model.Series.ToResource(),
SeasonNumber = model.SeasonNumber,
Episodes = model.Episodes.ToResource(),
Movie = model.Movie.ToResource(),
Quality = model.Quality,
//QualityWeight
DownloadId = model.DownloadId,

View File

@@ -1,8 +1,7 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Api.REST;
using NzbDrone.Api.Movie;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
@@ -11,7 +10,7 @@ using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR;
namespace NzbDrone.Api.EpisodeFiles
namespace NzbDrone.Api.MovieFiles
{
public class MovieFileModule : NzbDroneRestModuleWithSignalR<MovieFileResource, MovieFile>, IHandle<MovieFileAddedEvent>
{
@@ -72,4 +71,4 @@ namespace NzbDrone.Api.EpisodeFiles
BroadcastResourceChange(ModelAction.Updated, message.MovieFile.Id);
}
}
}
}

View File

@@ -1,14 +1,14 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Api.Movies;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.MovieFiles
{
public class MovieFileResource : RestResource
{

View File

@@ -4,7 +4,6 @@ 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;
@@ -18,7 +17,7 @@ using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class AlternativeTitleModule : NzbDroneRestModule<AlternativeTitleResource>
{
@@ -54,4 +53,4 @@ namespace NzbDrone.Api.Movie
return _altTitleService.GetById(id).ToResource();
}
}
}
}

View File

@@ -1,16 +1,15 @@
using System;
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
namespace NzbDrone.Api.Movies
{
public class AlternativeTitleResource : RestResource
{

View File

@@ -4,7 +4,6 @@ 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;
@@ -19,7 +18,7 @@ using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class AlternativeYearModule : NzbDroneRestModule<AlternativeYearResource>
{
@@ -60,4 +59,4 @@ namespace NzbDrone.Api.Movie
};
}
}
}
}

View File

@@ -1,16 +1,15 @@
using System;
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
namespace NzbDrone.Api.Movies
{
public class AlternativeYearResource : RestResource
{

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
@@ -6,7 +6,7 @@ using NzbDrone.Core.MetadataSource;
using System.Linq;
using NzbDrone.Core.NetImport;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class FetchMovieListModule : NzbDroneRestModule<MovieResource>
{
@@ -57,4 +57,4 @@ namespace NzbDrone.Api.Movie
}
}
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Collections;
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
@@ -16,7 +15,7 @@ using NzbDrone.Core.RootFolders;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class UnmappedComparer : IComparer<UnmappedFolder>

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
@@ -9,7 +9,7 @@ using NzbDrone.Api.REST;
using NzbDrone.Core.NetImport;
using NzbDrone.Api.NetImport;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class MovieDiscoverModule : NzbDroneRestModule<MovieResource>
{
@@ -60,4 +60,4 @@ namespace NzbDrone.Api.Movie
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
@@ -7,7 +7,7 @@ using NzbDrone.Api.Extensions;
using NzbDrone.Api.REST;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class MovieEditorModule : NzbDroneApiModule
{

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
@@ -7,7 +7,7 @@ using System.Linq;
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class MovieLookupModule : NzbDroneRestModule<MovieResource>
{
@@ -15,7 +15,7 @@ namespace NzbDrone.Api.Movie
private readonly IProvideMovieInfo _movieInfo;
public MovieLookupModule(ISearchForNewMovie searchProxy, IProvideMovieInfo movieInfo)
: base("/movies/lookup")
: base("/movie/lookup")
{
_movieInfo = movieInfo;
_searchProxy = searchProxy;
@@ -64,4 +64,4 @@ namespace NzbDrone.Api.Movie
}
}
}
}
}

View File

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

View File

@@ -1,4 +1,4 @@
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;

View File

@@ -1,12 +1,12 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv;
using NzbDrone.Api.Series;
using NzbDrone.Api.MovieFiles;
namespace NzbDrone.Api.Movie
namespace NzbDrone.Api.Movies
{
public class MovieResource : RestResource
{

View File

@@ -1,4 +1,4 @@
using NzbDrone.Api.REST;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaFiles;
using System;
using System.Collections.Generic;

View File

@@ -1,4 +1,4 @@
using NzbDrone.Api.REST;
using NzbDrone.Api.REST;
using System.Collections.Generic;
using System.Linq;

View File

@@ -1,34 +1,34 @@
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")
{
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();
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)
{
@@ -40,6 +40,6 @@ namespace NzbDrone.Api.NetImport
public void RemoveExclusion (int id)
{
_exclusionService.RemoveExclusion(new ImportExclusion { Id = id });
}
}
}
}
}
}

View File

@@ -1,46 +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
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
//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();
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
{
return new Core.NetImport.ImportExclusions.ImportExclusion
{
TmdbId = resource.TmdbId,
MovieTitle = resource.MovieTitle,
MovieYear = resource.MovieYear
MovieYear = resource.MovieYear
};
}
}
}
}
}
}

View File

@@ -1,9 +1,9 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using Nancy.Extensions;
using NzbDrone.Api.Extensions;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Tv;

View File

@@ -1,4 +1,3 @@
using NzbDrone.Core.NetImport;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.NetImport

View File

@@ -72,9 +72,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="NodaTime, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4226afe0d9b296d1, processorArchitecture=MSIL">
<HintPath>..\packages\Ical.Net.2.2.25\lib\net40\NodaTime.dll</HintPath>
@@ -115,17 +114,19 @@
<Compile Include="Extensions\Pipelines\CorsPipeline.cs" />
<Compile Include="Extensions\Pipelines\UrlBasePipeline.cs" />
<Compile Include="Extensions\Pipelines\RequestLoggingPipeline.cs" />
<Compile Include="ExtraFiles\ExtraFileResource.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="ExtraFiles\ExtraFileModule.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" />
<Compile Include="Series\MovieModule.cs" />
<Compile Include="MovieFiles\MovieFileModule.cs" />
<Compile Include="Movies\MovieModule.cs" />
<Compile Include="Movies\RenameMovieModule.cs" />
<Compile Include="Movies\RenameMovieResource.cs" />
<Compile Include="Movies\MovieEditorModule.cs" />
@@ -160,13 +161,6 @@
<Compile Include="DiskSpace\DiskSpaceResource.cs" />
<Compile Include="DownloadClient\DownloadClientModule.cs" />
<Compile Include="DownloadClient\DownloadClientResource.cs" />
<Compile Include="EpisodeFiles\EpisodeFileModule.cs" />
<Compile Include="EpisodeFiles\EpisodeFileResource.cs" />
<Compile Include="Episodes\EpisodeModule.cs" />
<Compile Include="Episodes\EpisodeModuleWithSignalR.cs" />
<Compile Include="Episodes\EpisodeResource.cs" />
<Compile Include="Episodes\RenameEpisodeModule.cs" />
<Compile Include="Episodes\RenameEpisodeResource.cs" />
<Compile Include="ErrorManagement\ApiException.cs" />
<Compile Include="ErrorManagement\ErrorHandler.cs" />
<Compile Include="ErrorManagement\ErrorModel.cs" />
@@ -242,19 +236,13 @@
<Compile Include="REST\RestResource.cs" />
<Compile Include="RootFolders\RootFolderModule.cs" />
<Compile Include="RootFolders\RootFolderResource.cs" />
<Compile Include="SeasonPass\SeasonPassResource.cs" />
<Compile Include="Series\AlternativeTitleResource.cs" />
<Compile Include="Series\MovieFileResource.cs" />
<Compile Include="Series\FetchMovieListModule.cs" />
<Compile Include="Series\SeasonResource.cs" />
<Compile Include="SeasonPass\SeasonPassModule.cs" />
<Compile Include="Series\SeriesEditorModule.cs" />
<Compile Include="Series\MovieLookupModule.cs" />
<Compile Include="Series\SeriesLookupModule.cs" />
<Compile Include="Movies\AlternativeTitleResource.cs" />
<Compile Include="MovieFiles\MovieFileResource.cs" />
<Compile Include="Movies\FetchMovieListModule.cs" />
<Compile Include="Movies\MovieLookupModule.cs" />
<Compile Include="Series\SeriesModule.cs" />
<Compile Include="Series\MovieResource.cs" />
<Compile Include="Movies\MovieResource.cs" />
<Compile Include="Series\SeriesResource.cs" />
<Compile Include="Series\SeasonStatisticsResource.cs" />
<Compile Include="System\Backup\BackupModule.cs" />
<Compile Include="System\Backup\BackupResource.cs" />
<Compile Include="System\Tasks\TaskModule.cs" />
@@ -269,12 +257,10 @@
<Compile Include="Validation\RssSyncIntervalValidator.cs" />
<Compile Include="Validation\EmptyCollectionValidator.cs" />
<Compile Include="Validation\RuleBuilderExtensions.cs" />
<Compile Include="Wanted\CutoffModule.cs" />
<Compile Include="Wanted\LegacyMissingModule.cs" />
<Compile Include="Wanted\MissingModule.cs" />
<Compile Include="Wanted\MovieCutoffModule.cs" />
<Compile Include="Wanted\MovieMissingModule.cs" />
<Compile Include="Series\MovieDiscoverModule.cs" />
<Compile Include="Movies\MovieDiscoverModule.cs" />
<Compile Include="NetImport\ImportExclusionsModule.cs" />
<Compile Include="NetImport\ImportExclusionsResource.cs" />
</ItemGroup>

View File

@@ -1,5 +1,4 @@
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Series;
using NzbDrone.Api.Movies;
using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Parse
@@ -18,23 +17,22 @@ namespace NzbDrone.Api.Parse
private ParseResource Parse()
{
var title = Request.Query.Title.Value as string;
var parsedEpisodeInfo = Parser.ParseTitle(title);
var parsedMovieInfo = Parser.ParseMovieTitle(title, false);
if (parsedEpisodeInfo == null)
if (parsedMovieInfo == null)
{
return null;
}
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0);
var remoteMovie = _parsingService.Map(parsedMovieInfo, "");
if (remoteEpisode != null)
if (remoteMovie != null)
{
return new ParseResource
{
Title = title,
ParsedEpisodeInfo = remoteEpisode.ParsedEpisodeInfo,
Series = remoteEpisode.Series.ToResource(),
Episodes = remoteEpisode.Episodes.ToResource()
ParsedMovieInfo = remoteMovie.RemoteMovie.ParsedMovieInfo,
Movie = remoteMovie.Movie.ToResource()
};
}
else
@@ -42,9 +40,9 @@ namespace NzbDrone.Api.Parse
return new ParseResource
{
Title = title,
ParsedEpisodeInfo = parsedEpisodeInfo
ParsedMovieInfo = parsedMovieInfo
};
}
}
}
}
}

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using NzbDrone.Api.Episodes;
using System.Collections.Generic;
using NzbDrone.Api.Movies;
using NzbDrone.Api.REST;
using NzbDrone.Api.Series;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Api.Parse
@@ -9,8 +8,7 @@ namespace NzbDrone.Api.Parse
public class ParseResource : RestResource
{
public string Title { get; set; }
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
public SeriesResource Series { get; set; }
public List<EpisodeResource> Episodes { get; set; }
public ParsedMovieInfo ParsedMovieInfo { get; set; }
public MovieResource Movie { get; set; }
}
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System;
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.Qualities;
using NzbDrone.Api.Series;
using NzbDrone.Api.Episodes;
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.Indexers;
using System.Linq;
@@ -13,8 +11,6 @@ namespace NzbDrone.Api.Queue
{
public class QueueResource : RestResource
{
public SeriesResource Series { get; set; }
public EpisodeResource Episode { get; set; }
public MovieResource Movie { get; set; }
public QualityModel Quality { get; set; }
public decimal Size { get; set; }
@@ -38,9 +34,6 @@ namespace NzbDrone.Api.Queue
return new QueueResource
{
Id = model.Id,
Series = model.Series.ToResource(),
Episode = model.Episode.ToResource(),
Quality = model.Quality,
Size = model.Size,
Title = model.Title,

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,31 +0,0 @@
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.SeasonPass
{
public class SeasonPassModule : NzbDroneApiModule
{
private readonly IEpisodeMonitoredService _episodeMonitoredService;
public SeasonPassModule(IEpisodeMonitoredService episodeMonitoredService)
: base("/seasonpass")
{
_episodeMonitoredService = episodeMonitoredService;
Post["/"] = series => UpdateAll();
}
private Response UpdateAll()
{
//Read from request
var request = Request.Body.FromJson<SeasonPassResource>();
foreach (var s in request.Series)
{
_episodeMonitoredService.SetEpisodeMonitoredStatus(s, request.MonitoringOptions);
}
return "ok".AsResponse(HttpStatusCode.Accepted);
}
}
}

View File

@@ -1,11 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.SeasonPass
{
public class SeasonPassResource
{
public List<Core.Tv.Series> Series { get; set; }
public MonitoringOptions MonitoringOptions { get; set; }
}
}

View File

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

View File

@@ -1,47 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Series
{
public class SeasonResource
{
public int SeasonNumber { get; set; }
public bool Monitored { get; set; }
public SeasonStatisticsResource Statistics { get; set; }
}
public static class SeasonResourceMapper
{
public static SeasonResource ToResource(this Season model)
{
if (model == null) return null;
return new SeasonResource
{
SeasonNumber = model.SeasonNumber,
Monitored = model.Monitored
};
}
public static Season ToModel(this SeasonResource resource)
{
if (resource == null) return null;
return new Season
{
SeasonNumber = resource.SeasonNumber,
Monitored = resource.Monitored
};
}
public static List<SeasonResource> ToResource(this IEnumerable<Season> models)
{
return models.Select(ToResource).ToList();
}
public static List<Season> ToModel(this IEnumerable<SeasonResource> resources)
{
return resources.Select(ToModel).ToList();
}
}
}

View File

@@ -1,43 +0,0 @@
using System;
using NzbDrone.Core.SeriesStats;
namespace NzbDrone.Api.Series
{
public class SeasonStatisticsResource
{
public DateTime? NextAiring { get; set; }
public DateTime? PreviousAiring { get; set; }
public int EpisodeFileCount { get; set; }
public int EpisodeCount { get; set; }
public int TotalEpisodeCount { get; set; }
public long SizeOnDisk { get; set; }
public decimal PercentOfEpisodes
{
get
{
if (EpisodeCount == 0) return 0;
return (decimal)EpisodeFileCount / (decimal)EpisodeCount * 100;
}
}
}
public static class SeasonStatisticsResourceMapper
{
public static SeasonStatisticsResource ToResource(this SeasonStatistics model)
{
if (model == null) return null;
return new SeasonStatisticsResource
{
NextAiring = model.NextAiring,
PreviousAiring = model.PreviousAiring,
EpisodeFileCount = model.EpisodeFileCount,
EpisodeCount = model.EpisodeFileCount,
TotalEpisodeCount = model.TotalEpisodeCount,
SizeOnDisk = model.SizeOnDisk
};
}
}
}

View File

@@ -1,31 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Series
{
public class SeriesEditorModule : NzbDroneApiModule
{
private readonly ISeriesService _seriesService;
public SeriesEditorModule(ISeriesService seriesService)
: base("/series/editor")
{
_seriesService = seriesService;
Put["/"] = series => SaveAll();
}
private Response SaveAll()
{
var resources = Request.Body.FromJson<List<SeriesResource>>();
var series = resources.Select(seriesResource => seriesResource.ToModel(_seriesService.GetSeries(seriesResource.Id))).ToList();
return _seriesService.UpdateSeries(series)
.ToResource()
.AsResponse(HttpStatusCode.Accepted);
}
}
}

View File

@@ -1,44 +0,0 @@
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MetadataSource;
using System.Linq;
namespace NzbDrone.Api.Series
{
public class SeriesLookupModule : NzbDroneRestModule<SeriesResource>
{
private readonly ISearchForNewSeries _searchProxy;
public SeriesLookupModule(ISearchForNewSeries searchProxy)
: base("/series/lookup")
{
_searchProxy = searchProxy;
Get["/"] = x => Search();
}
private Response Search()
{
var tvDbResults = _searchProxy.SearchForNewSeries((string)Request.Query.term);
return MapToResource(tvDbResults).AsResponse();
}
private static IEnumerable<SeriesResource> MapToResource(IEnumerable<Core.Tv.Series> series)
{
foreach (var currentSeries in series)
{
var resource = currentSeries.ToResource();
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
if (poster != null)
{
resource.RemotePoster = poster.Url;
}
yield return resource;
}
}
}
}

View File

@@ -1,242 +1,47 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.SeriesStats;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Validation;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Series
{
public class SeriesModule : NzbDroneRestModuleWithSignalR<SeriesResource, Core.Tv.Series>,
IHandle<EpisodeImportedEvent>,
IHandle<EpisodeFileDeletedEvent>,
IHandle<SeriesUpdatedEvent>,
IHandle<SeriesEditedEvent>,
IHandle<SeriesDeletedEvent>,
IHandle<SeriesRenamedEvent>,
IHandle<MediaCoversUpdatedEvent>
[Obsolete("SeriesModule is Obsolete, Remove with new UI")]
public class SeriesModule : NzbDroneRestModuleWithSignalR<SeriesResource, Core.Tv.Series>
{
private readonly ISeriesService _seriesService;
private readonly ISeriesStatisticsService _seriesStatisticsService;
private readonly ISceneMappingService _sceneMappingService;
private readonly IMapCoversToLocal _coverMapper;
public SeriesModule(IBroadcastSignalRMessage signalRBroadcaster,
ISeriesService seriesService,
ISeriesStatisticsService seriesStatisticsService,
ISceneMappingService sceneMappingService,
IMapCoversToLocal coverMapper,
RootFolderValidator rootFolderValidator,
SeriesPathValidator seriesPathValidator,
SeriesExistsValidator seriesExistsValidator,
DroneFactoryValidator droneFactoryValidator,
SeriesAncestorValidator seriesAncestorValidator,
ProfileExistsValidator profileExistsValidator
)
public SeriesModule(IBroadcastSignalRMessage signalRBroadcaster
)
: base(signalRBroadcaster)
{
_seriesService = seriesService;
_seriesStatisticsService = seriesStatisticsService;
_sceneMappingService = sceneMappingService;
_coverMapper = coverMapper;
GetResourceAll = AllSeries;
GetResourceById = GetSeries;
CreateResource = AddSeries;
UpdateResource = UpdateSeries;
DeleteResource = DeleteSeries;
Validation.RuleBuilderExtensions.ValidId(SharedValidator.RuleFor(s => s.ProfileId));
SharedValidator.RuleFor(s => s.Path)
.Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(seriesPathValidator)
.SetValidator(droneFactoryValidator)
.SetValidator(seriesAncestorValidator)
.When(s => !s.Path.IsNullOrWhiteSpace());
SharedValidator.RuleFor(s => s.ProfileId).SetValidator(profileExistsValidator);
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
PostValidator.RuleFor(s => s.Title).NotEmpty();
PostValidator.RuleFor(s => s.TvdbId).GreaterThan(0).SetValidator(seriesExistsValidator);
PutValidator.RuleFor(s => s.Path).IsValidPath();
}
private SeriesResource GetSeries(int id)
{
var series = _seriesService.GetSeries(id);
return MapToResource(series);
}
private SeriesResource MapToResource(Core.Tv.Series series)
{
if (series == null) return null;
var resource = series.ToResource();
MapCoversToLocal(resource);
FetchAndLinkSeriesStatistics(resource);
PopulateAlternateTitles(resource);
return resource;
return new SeriesResource();
}
private List<SeriesResource> AllSeries()
{
var seriesStats = _seriesStatisticsService.SeriesStatistics();
var seriesResources = _seriesService.GetAllSeries().ToResource();
MapCoversToLocal(seriesResources.ToArray());
LinkSeriesStatistics(seriesResources, seriesStats);
PopulateAlternateTitles(seriesResources);
return seriesResources;
return new List<SeriesResource>();
}
private int AddSeries(SeriesResource seriesResource)
{
var model = seriesResource.ToModel();
return _seriesService.AddSeries(model).Id;
return 0;
}
private void UpdateSeries(SeriesResource seriesResource)
{
var model = seriesResource.ToModel(_seriesService.GetSeries(seriesResource.Id));
_seriesService.UpdateSeries(model);
BroadcastResourceChange(ModelAction.Updated, seriesResource);
throw new NotImplementedException();
}
private void DeleteSeries(int id)
{
var deleteFiles = false;
var deleteFilesQuery = Request.Query.deleteFiles;
if (deleteFilesQuery.HasValue)
{
deleteFiles = Convert.ToBoolean(deleteFilesQuery.Value);
}
_seriesService.DeleteSeries(id, deleteFiles);
}
private void MapCoversToLocal(params SeriesResource[] series)
{
foreach (var seriesResource in series)
{
_coverMapper.ConvertToLocalUrls(seriesResource.Id, seriesResource.Images);
}
}
private void FetchAndLinkSeriesStatistics(SeriesResource resource)
{
LinkSeriesStatistics(resource, _seriesStatisticsService.SeriesStatistics(resource.Id));
}
private void LinkSeriesStatistics(List<SeriesResource> resources, List<SeriesStatistics> seriesStatistics)
{
var dictSeriesStats = seriesStatistics.ToDictionary(v => v.SeriesId);
foreach (var series in resources)
{
var stats = dictSeriesStats.GetValueOrDefault(series.Id);
if (stats == null) continue;
LinkSeriesStatistics(series, stats);
}
}
private void LinkSeriesStatistics(SeriesResource resource, SeriesStatistics seriesStatistics)
{
resource.TotalEpisodeCount = seriesStatistics.TotalEpisodeCount;
resource.EpisodeCount = seriesStatistics.EpisodeCount;
resource.EpisodeFileCount = seriesStatistics.EpisodeFileCount;
resource.NextAiring = seriesStatistics.NextAiring;
resource.PreviousAiring = seriesStatistics.PreviousAiring;
resource.SizeOnDisk = seriesStatistics.SizeOnDisk;
if (seriesStatistics.SeasonStatistics != null)
{
var dictSeasonStats = seriesStatistics.SeasonStatistics.ToDictionary(v => v.SeasonNumber);
foreach (var season in resource.Seasons)
{
season.Statistics = SeasonStatisticsResourceMapper.ToResource(dictSeasonStats.GetValueOrDefault(season.SeasonNumber));
}
}
}
private void PopulateAlternateTitles(List<SeriesResource> resources)
{
foreach (var resource in resources)
{
PopulateAlternateTitles(resource);
}
}
private void PopulateAlternateTitles(SeriesResource resource)
{
var mappings = _sceneMappingService.FindByTvdbId(resource.TvdbId);
if (mappings == null) return;
//resource.AlternateTitles = mappings.Select(v => new AlternateTitleResource { Title = v.Title, SeasonNumber = v.SeasonNumber, SceneSeasonNumber = v.SceneSeasonNumber }).ToList();
}
public void Handle(EpisodeImportedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.ImportedEpisode.SeriesId);
}
public void Handle(EpisodeFileDeletedEvent message)
{
if (message.Reason == DeleteMediaFileReason.Upgrade) return;
BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.SeriesId);
}
public void Handle(SeriesUpdatedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
}
public void Handle(SeriesEditedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
}
public void Handle(SeriesDeletedEvent message)
{
BroadcastResourceChange(ModelAction.Deleted, message.Series.ToResource());
}
public void Handle(SeriesRenamedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
}
public void Handle(MediaCoversUpdatedEvent message)
{
//BroadcastResourceChange(ModelAction.Updated, message.Series.Id);
throw new NotImplementedException();
}
}
}

View File

@@ -1,232 +1,19 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Series
{
[Obsolete("SeriesResource is Obsolete, Remove with new UI")]
public class SeriesResource : RestResource
{
public SeriesResource()
{
Monitored = true;
Title = "Series Endpoint Obsolete";
}
//Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately
//View Only
public string Title { get; set; }
//public List<AlternativeTitleResource> AlternateTitles { get; set; }
public string SortTitle { get; set; }
public int SeasonCount
{
get
{
if (Seasons == null) return 0;
return Seasons.Where(s => s.SeasonNumber > 0).Count();
}
}
public int? TotalEpisodeCount { get; set; }
public int? EpisodeCount { get; set; }
public int? EpisodeFileCount { get; set; }
public long? SizeOnDisk { get; set; }
public SeriesStatusType Status { get; set; }
public string Overview { get; set; }
public DateTime? NextAiring { get; set; }
public DateTime? PreviousAiring { get; set; }
public string Network { get; set; }
public string AirTime { get; set; }
public List<MediaCover> Images { get; set; }
public string RemotePoster { get; set; }
public List<SeasonResource> Seasons { get; set; }
public int Year { get; set; }
//View & Edit
public string Path { get; set; }
public int ProfileId { get; set; }
//Editing Only
public bool SeasonFolder { get; set; }
public bool Monitored { get; set; }
public bool UseSceneNumbering { get; set; }
public int Runtime { get; set; }
public int TvdbId { get; set; }
public int TvRageId { get; set; }
public int TvMazeId { get; set; }
public DateTime? FirstAired { get; set; }
public DateTime? LastInfoSync { get; set; }
public SeriesTypes SeriesType { get; set; }
public string CleanTitle { get; set; }
public string ImdbId { get; set; }
public string TitleSlug { get; set; }
public string RootFolderPath { get; set; }
public string Certification { get; set; }
public List<string> Genres { get; set; }
public HashSet<int> Tags { get; set; }
public DateTime Added { get; set; }
public AddSeriesOptions AddOptions { get; set; }
public Ratings Ratings { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
//Used to support legacy consumers
public int QualityProfileId
{
get
{
return ProfileId;
}
set
{
if (value > 0 && ProfileId == 0)
{
ProfileId = value;
}
}
}
}
public static class SeriesResourceMapper
{
public static SeriesResource ToResource(this Core.Tv.Series model)
{
if (model == null) return null;
return new SeriesResource
{
Id = model.Id,
Title = model.Title,
//AlternateTitles
SortTitle = model.SortTitle,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
//SizeOnDisk
Status = model.Status,
Overview = model.Overview,
//NextAiring
//PreviousAiring
Network = model.Network,
AirTime = model.AirTime,
Images = model.Images,
Seasons = model.Seasons.ToResource(),
Year = model.Year,
Path = model.Path,
ProfileId = model.ProfileId,
SeasonFolder = model.SeasonFolder,
Monitored = model.Monitored,
UseSceneNumbering = model.UseSceneNumbering,
Runtime = model.Runtime,
TvdbId = model.TvdbId,
TvRageId = model.TvRageId,
TvMazeId = model.TvMazeId,
FirstAired = model.FirstAired,
LastInfoSync = model.LastInfoSync,
SeriesType = model.SeriesType,
CleanTitle = model.CleanTitle,
ImdbId = model.ImdbId,
TitleSlug = model.TitleSlug,
RootFolderPath = model.RootFolderPath,
Certification = model.Certification,
Genres = model.Genres,
Tags = model.Tags,
Added = model.Added,
AddOptions = model.AddOptions,
Ratings = model.Ratings
};
}
public static Core.Tv.Series ToModel(this SeriesResource resource)
{
if (resource == null) return null;
return new Core.Tv.Series
{
Id = resource.Id,
Title = resource.Title,
//AlternateTitles
SortTitle = resource.SortTitle,
//TotalEpisodeCount
//EpisodeCount
//EpisodeFileCount
//SizeOnDisk
Status = resource.Status,
Overview = resource.Overview,
//NextAiring
//PreviousAiring
Network = resource.Network,
AirTime = resource.AirTime,
Images = resource.Images,
Seasons = resource.Seasons.ToModel(),
Year = resource.Year,
Path = resource.Path,
ProfileId = resource.ProfileId,
SeasonFolder = resource.SeasonFolder,
Monitored = resource.Monitored,
UseSceneNumbering = resource.UseSceneNumbering,
Runtime = resource.Runtime,
TvdbId = resource.TvdbId,
TvRageId = resource.TvRageId,
TvMazeId = resource.TvMazeId,
FirstAired = resource.FirstAired,
LastInfoSync = resource.LastInfoSync,
SeriesType = resource.SeriesType,
CleanTitle = resource.CleanTitle,
ImdbId = resource.ImdbId,
TitleSlug = resource.TitleSlug,
RootFolderPath = resource.RootFolderPath,
Certification = resource.Certification,
Genres = resource.Genres,
Tags = resource.Tags,
Added = resource.Added,
AddOptions = resource.AddOptions,
Ratings = resource.Ratings
};
}
public static Core.Tv.Series ToModel(this SeriesResource resource, Core.Tv.Series series)
{
series.TvdbId = resource.TvdbId;
series.Seasons = resource.Seasons.ToModel();
series.Path = resource.Path;
series.ProfileId = resource.ProfileId;
series.SeasonFolder = resource.SeasonFolder;
series.Monitored = resource.Monitored;
series.SeriesType = resource.SeriesType;
series.RootFolderPath = resource.RootFolderPath;
series.Tags = resource.Tags;
series.AddOptions = resource.AddOptions;
return series;
}
public static List<SeriesResource> ToResource(this IEnumerable<Core.Tv.Series> series)
{
return series.Select(ToResource).ToList();
}
}
}

View File

@@ -21,9 +21,9 @@ namespace NzbDrone.Api.System.Backup
return backups.Select(b => new BackupResource
{
Id = b.Path.GetHashCode(),
Name = Path.GetFileName(b.Path),
Path = b.Path,
Id = b.Name.GetHashCode(),
Name = b.Name,
Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}",
Type = b.Type,
Time = b.Time
}).ToList();

View File

@@ -1,42 +0,0 @@
using NzbDrone.Api.Episodes;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Wanted
{
public class CutoffModule : EpisodeModuleWithSignalR
{
private readonly IEpisodeCutoffService _episodeCutoffService;
public CutoffModule(IEpisodeCutoffService episodeCutoffService,
IEpisodeService episodeService,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/cutoff-old")
{
_episodeCutoffService = episodeCutoffService;
GetResourcePaged = GetCutoffUnmetEpisodes;
}
private PagingResource<EpisodeResource> GetCutoffUnmetEpisodes(PagingResource<EpisodeResource> pagingResource)
{
var pagingSpec = pagingResource.MapToPagingSpec<EpisodeResource, Episode>("airDateUtc", SortDirection.Descending);
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
{
pagingSpec.FilterExpression = v => v.Monitored == false || v.Series.Monitored == false;
}
else
{
pagingSpec.FilterExpression = v => v.Monitored == true && v.Series.Monitored == true;
}
var resource = ApplyToPage(_episodeCutoffService.EpisodesWhereCutoffUnmet, pagingSpec, v => MapToResource(v, true, true));
return resource;
}
}
}

View File

@@ -1,38 +0,0 @@
using NzbDrone.Api.Episodes;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
using NzbDrone.SignalR;
namespace NzbDrone.Api.Wanted
{
public class MissingModule : EpisodeModuleWithSignalR
{
public MissingModule(IEpisodeService episodeService,
ISeriesService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
IBroadcastSignalRMessage signalRBroadcaster)
: base(episodeService, seriesService, qualityUpgradableSpecification, signalRBroadcaster, "wanted/missing_episodes")
{
GetResourcePaged = GetMissingEpisodes;
}
private PagingResource<EpisodeResource> GetMissingEpisodes(PagingResource<EpisodeResource> pagingResource)
{
var pagingSpec = pagingResource.MapToPagingSpec<EpisodeResource, Episode>("airDateUtc", SortDirection.Descending);
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
{
pagingSpec.FilterExpression = v => v.Monitored == false || v.Series.Monitored == false;
}
else
{
pagingSpec.FilterExpression = v => v.Monitored == true && v.Series.Monitored == true;
}
var resource = ApplyToPage(_episodeService.EpisodesWithoutFiles, pagingSpec, v => MapToResource(v, true, false));
return resource;
}
}
}

View File

@@ -1,4 +1,3 @@
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;
@@ -32,4 +31,4 @@ namespace NzbDrone.Api.Wanted
return resource;
}
}
}
}

View File

@@ -1,4 +1,3 @@
using NzbDrone.Api.Movie;
using NzbDrone.Api.Movies;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Tv;

View File

@@ -6,5 +6,5 @@
<package id="Nancy.Authentication.Basic" version="1.4.1" targetFramework="net40" />
<package id="Nancy.Authentication.Forms" version="1.4.1" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
<package id="NLog" version="4.3.11" targetFramework="net40" />
<package id="NLog" version="4.4.12" targetFramework="net40" />
</packages>

View File

@@ -49,9 +49,8 @@
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>

View File

@@ -3,6 +3,6 @@
<package id="FluentAssertions" version="4.18.0" targetFramework="net40" />
<package id="Moq" version="4.0.10827" />
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
<package id="NLog" version="4.3.11" targetFramework="net40" />
<package id="NLog" version="4.4.12" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
</packages>

View File

@@ -46,9 +46,8 @@
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>

View File

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

View File

@@ -45,9 +45,8 @@
<HintPath>..\packages\FluentAssertions.4.18.0\lib\net40\FluentAssertions.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>

View File

@@ -2,6 +2,6 @@
<packages>
<package id="FluentAssertions" version="4.18.0" targetFramework="net40" />
<package id="Moq" version="4.0.10827" />
<package id="NLog" version="4.3.11" targetFramework="net40" />
<package id="NLog" version="4.4.12" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
</packages>

View File

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

@@ -43,9 +43,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="Org.Mentalis, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DotNet4.SocksProxy.1.3.2.0\lib\net40\Org.Mentalis.dll</HintPath>
@@ -259,4 +258,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -98,9 +98,9 @@ namespace NzbDrone.Common.Processes
var process = new Process
{
StartInfo = new ProcessStartInfo(url)
{
UseShellExecute = true
}
{
UseShellExecute = true
}
};
process.Start();
@@ -129,16 +129,34 @@ namespace NzbDrone.Common.Processes
{
foreach (DictionaryEntry environmentVariable in environmentVariables)
{
startInfo.EnvironmentVariables.Add(environmentVariable.Key.ToString(), environmentVariable.Value.ToString());
try
{
_logger.Trace("Setting environment variable '{0}' to '{1}'", environmentVariable.Key, environmentVariable.Value);
startInfo.EnvironmentVariables.Add(environmentVariable.Key.ToString(), environmentVariable.Value.ToString());
}
catch (Exception e)
{
if (environmentVariable.Value == null)
{
_logger.Error(e, "Unable to set environment variable '{0}', value is null", environmentVariable.Key);
}
else
{
_logger.Error(e, "Unable to set environment variable '{0}'", environmentVariable.Key);
}
throw;
}
}
}
logger.Debug("Starting {0} {1}", path, args);
var process = new Process
{
StartInfo = startInfo
};
{
StartInfo = startInfo
};
process.OutputDataReceived += (sender, eventArgs) =>
{
@@ -315,7 +333,7 @@ namespace NzbDrone.Common.Processes
var monoProcesses = Process.GetProcessesByName("mono")
.Union(Process.GetProcessesByName("mono-sgen"))
.Union(Process.GetProcessesByName("mono-sgen32"))
.Union(Process.GetProcessesByName("mono-sgen32"))
.Where(process =>
process.Modules.Cast<ProcessModule>()
.Any(module =>

View File

@@ -3,5 +3,5 @@
<package id="DotNet4.SocksProxy" version="1.3.2.0" targetFramework="net40" />
<package id="ICSharpCode.SharpZipLib.Patched" version="0.86.5" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
<package id="NLog" version="4.3.11" targetFramework="net40" />
<package id="NLog" version="4.4.12" targetFramework="net40" />
</packages>

View File

@@ -75,9 +75,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View File

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

View File

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

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

View File

@@ -328,7 +328,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
result.IsLocalhost.Should().BeTrue();
result.OutputRootFolders.Should().NotBeNull();
result.OutputRootFolders.First().Should().Be(@"C:\Downloads\Finished\utorrent\tv".AsOsAgnostic());
result.OutputRootFolders.First().Should().Be(@"C:\Downloads\Finished\utorrent\movie".AsOsAgnostic());
}
[Test]

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,27 +20,27 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
public class DeleteBadMediaCoversFixture : CoreTest<DeleteBadMediaCovers>
{
private List<MetadataFile> _metadata;
private List<Series> _series;
private List<Movie> _movies;
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateListOfSize(1)
_movies = Builder<Movie>.CreateListOfSize(1)
.All()
.With(c => c.Path = "C:\\TV\\".AsOsAgnostic())
.With(c => c.Path = "C:\\Movie\\".AsOsAgnostic())
.Build().ToList();
_metadata = Builder<MetadataFile>.CreateListOfSize(1)
.Build().ToList();
Mocker.GetMock<ISeriesService>()
.Setup(c => c.GetAllSeries())
.Returns(_series);
Mocker.GetMock<IMovieService>()
.Setup(c => c.GetAllMovies())
.Returns(_movies);
Mocker.GetMock<IMetadataFileService>()
.Setup(c => c.GetFilesBySeries(_series.First().Id))
.Setup(c => c.GetFilesByMovie(_movies.First().Id))
.Returns(_metadata);
@@ -51,8 +51,8 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[Test]
public void should_not_process_non_image_files()
{
_metadata.First().RelativePath = "season\\file.xml".AsOsAgnostic();
_metadata.First().Type = MetadataType.EpisodeMetadata;
_metadata.First().RelativePath = "extrafiles\\file.xml".AsOsAgnostic();
_metadata.First().Type = MetadataType.MovieMetadata;
Subject.Clean();
@@ -101,10 +101,10 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
public void should_delete_html_images()
{
var imagePath = "C:\\TV\\Season\\image.jpg".AsOsAgnostic();
var imagePath = "C:\\Movie\\image.jpg".AsOsAgnostic();
_metadata.First().LastUpdated = new DateTime(2014, 12, 29);
_metadata.First().RelativePath = "Season\\image.jpg".AsOsAgnostic();
_metadata.First().Type = MetadataType.SeriesImage;
_metadata.First().RelativePath = "image.jpg".AsOsAgnostic();
_metadata.First().Type = MetadataType.MovieImage;
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.OpenReadStream(imagePath))
@@ -123,10 +123,10 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
public void should_delete_empty_images()
{
var imagePath = "C:\\TV\\Season\\image.jpg".AsOsAgnostic();
var imagePath = "C:\\Movie\\image.jpg".AsOsAgnostic();
_metadata.First().LastUpdated = new DateTime(2014, 12, 29);
_metadata.First().Type = MetadataType.SeasonImage;
_metadata.First().RelativePath = "Season\\image.jpg".AsOsAgnostic();
_metadata.First().Type = MetadataType.MovieImage;
_metadata.First().RelativePath = "image.jpg".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.OpenReadStream(imagePath))
@@ -144,9 +144,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
public void should_not_delete_non_html_files()
{
var imagePath = "C:\\TV\\Season\\image.jpg".AsOsAgnostic();
var imagePath = "C:\\Movie\\image.jpg".AsOsAgnostic();
_metadata.First().LastUpdated = new DateTime(2014, 12, 29);
_metadata.First().RelativePath = "Season\\image.jpg".AsOsAgnostic();
_metadata.First().RelativePath = "image.jpg".AsOsAgnostic();
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.OpenReadStream(imagePath))

View File

@@ -1,4 +1,4 @@
using FizzWare.NBuilder;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Extras.Metadata;
@@ -12,12 +12,12 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
public class CleanupDuplicateMetadataFilesFixture : DbTest<CleanupDuplicateMetadataFiles, MetadataFile>
{
[Test]
public void should_not_delete_metadata_files_when_they_are_for_the_same_series_but_different_consumers()
public void should_not_delete_metadata_files_when_they_are_for_the_same_movie_but_different_consumers()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.SeriesMetadata)
.With(m => m.SeriesId = 1)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.MovieId = 1)
.BuildListOfNew();
Db.InsertMany(files);
@@ -26,11 +26,11 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_for_different_series()
public void should_not_delete_metadata_files_for_different_movie()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.SeriesMetadata)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.Consumer = "XbmcMetadata")
.BuildListOfNew();
@@ -40,12 +40,12 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_delete_metadata_files_when_they_are_for_the_same_series_and_consumer()
public void should_delete_metadata_files_when_they_are_for_the_same_movie_and_consumer()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.SeriesMetadata)
.With(m => m.SeriesId = 1)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.MovieId = 1)
.With(m => m.Consumer = "XbmcMetadata")
.BuildListOfNew();
@@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_when_there_is_only_one_for_that_series_and_consumer()
public void should_not_delete_metadata_files_when_there_is_only_one_for_that_movie_and_consumer()
{
var file = Builder<MetadataFile>.CreateNew()
.BuildNew();
@@ -66,12 +66,12 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_when_they_are_for_the_same_episode_but_different_consumers()
public void should_not_delete_metadata_files_when_they_are_for_the_same_movie_file_but_different_consumers()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.EpisodeMetadata)
.With(m => m.EpisodeFileId = 1)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.MovieFileId = 1)
.BuildListOfNew();
Db.InsertMany(files);
@@ -80,11 +80,11 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_for_different_episode()
public void should_not_delete_metadata_files_for_different_movie_file()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.EpisodeMetadata)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.Consumer = "XbmcMetadata")
.BuildListOfNew();
@@ -94,12 +94,12 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_delete_metadata_files_when_they_are_for_the_same_episode_and_consumer()
public void should_delete_metadata_files_when_they_are_for_the_same_movie_file_and_consumer()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.EpisodeMetadata)
.With(m => m.EpisodeFileId = 1)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.MovieFileId = 1)
.With(m => m.Consumer = "XbmcMetadata")
.BuildListOfNew();
@@ -109,7 +109,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_when_there_is_only_one_for_that_episode_and_consumer()
public void should_not_delete_metadata_files_when_there_is_only_one_for_that_movie_file_and_consumer()
{
var file = Builder<MetadataFile>.CreateNew()
.BuildNew();
@@ -120,12 +120,12 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_image_when_they_are_for_the_same_episode_but_different_consumers()
public void should_not_delete_image_when_they_are_for_the_same_movie_file_but_different_consumers()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.EpisodeImage)
.With(m => m.EpisodeFileId = 1)
.With(m => m.Type = MetadataType.MovieImage)
.With(m => m.MovieFileId = 1)
.BuildListOfNew();
Db.InsertMany(files);
@@ -134,11 +134,11 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_image_for_different_episode()
public void should_not_delete_image_for_different_movie_file()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.EpisodeImage)
.With(m => m.Type = MetadataType.MovieImage)
.With(m => m.Consumer = "XbmcMetadata")
.BuildListOfNew();
@@ -148,22 +148,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_delete_image_when_they_are_for_the_same_episode_and_consumer()
{
var files = Builder<MetadataFile>.CreateListOfSize(2)
.All()
.With(m => m.Type = MetadataType.EpisodeImage)
.With(m => m.EpisodeFileId = 1)
.With(m => m.Consumer = "XbmcMetadata")
.BuildListOfNew();
Db.InsertMany(files);
Subject.Clean();
AllStoredModels.Count.Should().Be(1);
}
[Test]
public void should_not_delete_image_when_there_is_only_one_for_that_episode_and_consumer()
public void should_not_delete_image_when_there_is_only_one_for_that_movie_file_and_consumer()
{
var file = Builder<MetadataFile>.CreateNew()
.BuildNew();

View File

@@ -1,4 +1,4 @@
using FizzWare.NBuilder;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Extras.Metadata;
@@ -15,10 +15,10 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
public class CleanupOrphanedMetadataFilesFixture : DbTest<CleanupOrphanedMetadataFiles, MetadataFile>
{
[Test]
public void should_delete_metadata_files_that_dont_have_a_coresponding_series()
public void should_delete_metadata_files_that_dont_have_a_coresponding_movie()
{
var metadataFile = Builder<MetadataFile>.CreateNew()
.With(m => m.EpisodeFileId = null)
.With(m => m.MovieFileId = null)
.BuildNew();
Db.Insert(metadataFile);
@@ -27,16 +27,16 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_that_have_a_coresponding_series()
public void should_not_delete_metadata_files_that_have_a_coresponding_movie()
{
var series = Builder<Series>.CreateNew()
var movie = Builder<Movie>.CreateNew()
.BuildNew();
Db.Insert(series);
Db.Insert(movie);
var metadataFile = Builder<MetadataFile>.CreateNew()
.With(m => m.SeriesId = series.Id)
.With(m => m.EpisodeFileId = null)
.With(m => m.MovieId = movie.Id)
.With(m => m.MovieFileId = null)
.BuildNew();
Db.Insert(metadataFile);
@@ -45,16 +45,16 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_delete_metadata_files_that_dont_have_a_coresponding_episode_file()
public void should_delete_metadata_files_that_dont_have_a_coresponding_movie_file()
{
var series = Builder<Series>.CreateNew()
var movie = Builder<Movie>.CreateNew()
.BuildNew();
Db.Insert(series);
Db.Insert(movie);
var metadataFile = Builder<MetadataFile>.CreateNew()
.With(m => m.SeriesId = series.Id)
.With(m => m.EpisodeFileId = 10)
.With(m => m.MovieId = movie.Id)
.With(m => m.MovieFileId = 10)
.BuildNew();
Db.Insert(metadataFile);
@@ -63,21 +63,21 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_not_delete_metadata_files_that_have_a_coresponding_episode_file()
public void should_not_delete_metadata_files_that_have_a_coresponding_movie_file()
{
var series = Builder<Series>.CreateNew()
var movie = Builder<Movie>.CreateNew()
.BuildNew();
var episodeFile = Builder<EpisodeFile>.CreateNew()
var movieFile = Builder<MovieFile>.CreateNew()
.With(h => h.Quality = new QualityModel())
.BuildNew();
Db.Insert(series);
Db.Insert(episodeFile);
Db.Insert(movie);
Db.Insert(movieFile);
var metadataFile = Builder<MetadataFile>.CreateNew()
.With(m => m.SeriesId = series.Id)
.With(m => m.EpisodeFileId = episodeFile.Id)
.With(m => m.MovieId = movie.Id)
.With(m => m.MovieFileId = movieFile.Id)
.BuildNew();
Db.Insert(metadataFile);
@@ -86,17 +86,17 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_delete_episode_metadata_files_that_have_episodefileid_of_zero()
public void should_delete_movie_metadata_files_that_have_moviefileid_of_zero()
{
var series = Builder<Series>.CreateNew()
var movie = Builder<Movie>.CreateNew()
.BuildNew();
Db.Insert(series);
Db.Insert(movie);
var metadataFile = Builder<MetadataFile>.CreateNew()
.With(m => m.SeriesId = series.Id)
.With(m => m.Type = MetadataType.EpisodeMetadata)
.With(m => m.EpisodeFileId = 0)
.With(m => m.MovieId = movie.Id)
.With(m => m.Type = MetadataType.MovieMetadata)
.With(m => m.MovieFileId = 0)
.BuildNew();
Db.Insert(metadataFile);
@@ -105,17 +105,17 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
}
[Test]
public void should_delete_episode_image_files_that_have_episodefileid_of_zero()
public void should_delete_movie_image_files_that_have_moviefileid_of_zero()
{
var series = Builder<Series>.CreateNew()
var movie = Builder<Movie>.CreateNew()
.BuildNew();
Db.Insert(series);
Db.Insert(movie);
var metadataFile = Builder<MetadataFile>.CreateNew()
.With(m => m.SeriesId = series.Id)
.With(m => m.Type = MetadataType.EpisodeImage)
.With(m => m.EpisodeFileId = 0)
.With(m => m.MovieId = movie.Id)
.With(m => m.Type = MetadataType.MovieImage)
.With(m => m.MovieFileId = 0)
.BuildNew();
Db.Insert(metadataFile);

View File

@@ -47,7 +47,7 @@ namespace NzbDrone.Core.Test.MediaCoverTests
Subject.ConvertToLocalUrls(12, covers);
covers.Single().Url.Should().Be("/MediaCover/12/banner.jpg?lastWrite=1234");
covers.Single().Url.Should().Be("/MediaCover/12/banner.jpg");
}
[Test]

View File

@@ -14,6 +14,7 @@ using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
using FluentAssertions;
using NzbDrone.Core.Download;
namespace NzbDrone.Core.Test.MediaFiles
{
@@ -77,7 +78,7 @@ namespace NzbDrone.Core.Test.MediaFiles
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IMakeImportDecision>()
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<ParsedMovieInfo>(), It.IsAny<bool>()),
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), It.IsAny<ParsedMovieInfo>(), It.IsAny<bool>()),
Times.Never());
VerifyNoImport();
@@ -128,7 +129,7 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localMovie));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedMovie>()
@@ -154,7 +155,7 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localMovie));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedMovie>()
@@ -226,7 +227,7 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localMovie));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedMovie>()
@@ -280,7 +281,7 @@ namespace NzbDrone.Core.Test.MediaFiles
Subject.ProcessPath(fileName);
Mocker.GetMock<IMakeImportDecision>()
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<ParsedMovieInfo>(), true, false), Times.Once());
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), It.IsAny<ParsedMovieInfo>(), true, false), Times.Once());
}
[Test]
@@ -304,7 +305,7 @@ namespace NzbDrone.Core.Test.MediaFiles
var result = Subject.ProcessPath(fileName);
Mocker.GetMock<IMakeImportDecision>()
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true, false), Times.Once());
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true, false), Times.Once());
}
[Test]
@@ -337,7 +338,7 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localMovie));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), null, true))
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Movie>(), It.IsAny<DownloadClientItem>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedEpisodes>()

View File

@@ -0,0 +1,67 @@
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Marr.Data;
using NUnit.Framework;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
{
[TestFixture]
public class SameFileSpecificationFixture : CoreTest<SameFileSpecification>
{
private LocalMovie _localMovie;
[SetUp]
public void Setup()
{
_localMovie = Builder<LocalMovie>.CreateNew()
.With(l => l.Size = 150.Megabytes())
.Build();
}
[Test]
public void should_be_accepted_if_no_existing_file()
{
_localMovie.Movie = Builder<Movie>.CreateNew()
.With(e => e.MovieFileId = 0)
.Build();
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_accepted_if_file_size_is_different()
{
_localMovie.Movie = Builder<Movie>.CreateNew()
.With(e => e.MovieFileId = 1)
.With(e => e.MovieFile = new LazyLoaded<MovieFile>(
new MovieFile
{
Size = _localMovie.Size + 100.Megabytes()
}))
.Build();
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeTrue();
}
[Test]
public void should_be_reject_if_file_size_is_the_same()
{
_localMovie.Movie = Builder<Movie>.CreateNew()
.With(e => e.MovieFileId = 1)
.With(e => e.MovieFile = new LazyLoaded<MovieFile>(
new MovieFile
{
Size = _localMovie.Size
}))
.Build();
Subject.IsSatisfiedBy(_localMovie, null).Accepted.Should().BeFalse();
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
@@ -13,66 +13,56 @@ namespace NzbDrone.Core.Test.Metadata.Consumers.Roksbox
[TestFixture]
public class FindMetadataFileFixture : CoreTest<RoksboxMetadata>
{
private Series _series;
private Movie _movie;
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateNew()
.With(s => s.Path = @"C:\Test\TV\The.Series".AsOsAgnostic())
_movie = Builder<Movie>.CreateNew()
.With(s => s.Path = @"C:\Test\Movies\The.Movie.2011".AsOsAgnostic())
.Build();
}
[Test]
public void should_return_null_if_filename_is_not_handled()
{
var path = Path.Combine(_series.Path, "file.jpg");
var path = Path.Combine(_movie.Path, "file.jpg");
Subject.FindMetadataFile(_series, path).Should().BeNull();
Subject.FindMetadataFile(_movie, path).Should().BeNull();
}
[TestCase("Specials")]
[TestCase("specials")]
[TestCase("Season 1")]
public void should_return_season_image(string folder)
[TestCase(".xml", MetadataType.MovieMetadata)]
[TestCase(".jpg", MetadataType.MovieImage)]
public void should_return_metadata_for_movie_if_valid_file_for_movie(string extension, MetadataType type)
{
var path = Path.Combine(_series.Path, folder, folder + ".jpg");
var path = Path.Combine(_movie.Path, "the.movie.2011" + extension);
Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.SeasonImage);
}
[TestCase(".xml", MetadataType.EpisodeMetadata)]
[TestCase(".jpg", MetadataType.EpisodeImage)]
public void should_return_metadata_for_episode_if_valid_file_for_episode(string extension, MetadataType type)
{
var path = Path.Combine(_series.Path, "the.series.s01e01.episode" + extension);
Subject.FindMetadataFile(_series, path).Type.Should().Be(type);
Subject.FindMetadataFile(_movie, path).Type.Should().Be(type);
}
[TestCase(".xml")]
[TestCase(".jpg")]
public void should_return_null_if_not_valid_file_for_episode(string extension)
public void should_return_null_if_not_valid_file_for_movie(string extension)
{
var path = Path.Combine(_series.Path, "the.series.episode" + extension);
var path = Path.Combine(_movie.Path, "the.movie.here" + extension);
Subject.FindMetadataFile(_series, path).Should().BeNull();
Subject.FindMetadataFile(_movie, path).Should().BeNull();
}
[Test]
public void should_not_return_metadata_if_image_file_is_a_thumb()
{
var path = Path.Combine(_series.Path, "the.series.s01e01.episode-thumb.jpg");
var path = Path.Combine(_movie.Path, "the.movie.2011-thumb.jpg");
Subject.FindMetadataFile(_series, path).Should().BeNull();
Subject.FindMetadataFile(_movie, path).Should().BeNull();
}
[Test]
public void should_return_series_image_for_folder_jpg_in_series_folder()
public void should_return_movie_image_for_folder_jpg_in_movie_folder()
{
var path = Path.Combine(_series.Path, new DirectoryInfo(_series.Path).Name + ".jpg");
var path = Path.Combine(_movie.Path, new DirectoryInfo(_movie.Path).Name + ".jpg");
Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.SeriesImage);
Subject.FindMetadataFile(_movie, path).Type.Should().Be(MetadataType.MovieImage);
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
@@ -13,58 +13,48 @@ namespace NzbDrone.Core.Test.Metadata.Consumers.Wdtv
[TestFixture]
public class FindMetadataFileFixture : CoreTest<WdtvMetadata>
{
private Series _series;
private Movie _movie;
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateNew()
.With(s => s.Path = @"C:\Test\TV\The.Series".AsOsAgnostic())
_movie = Builder<Movie>.CreateNew()
.With(s => s.Path = @"C:\Test\Movies\The.Movie".AsOsAgnostic())
.Build();
}
[Test]
public void should_return_null_if_filename_is_not_handled()
{
var path = Path.Combine(_series.Path, "file.jpg");
var path = Path.Combine(_movie.Path, "file.jpg");
Subject.FindMetadataFile(_series, path).Should().BeNull();
Subject.FindMetadataFile(_movie, path).Should().BeNull();
}
[TestCase("Specials")]
[TestCase("specials")]
[TestCase("Season 1")]
public void should_return_season_image(string folder)
[TestCase(".xml", MetadataType.MovieMetadata)]
[TestCase(".metathumb", MetadataType.MovieImage)]
public void should_return_metadata_for_movie_if_valid_file_for_movie(string extension, MetadataType type)
{
var path = Path.Combine(_series.Path, folder, "folder.jpg");
var path = Path.Combine(_movie.Path, "the.movie.2011" + extension);
Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.SeasonImage);
}
[TestCase(".xml", MetadataType.EpisodeMetadata)]
[TestCase(".metathumb", MetadataType.EpisodeImage)]
public void should_return_metadata_for_episode_if_valid_file_for_episode(string extension, MetadataType type)
{
var path = Path.Combine(_series.Path, "the.series.s01e01.episode" + extension);
Subject.FindMetadataFile(_series, path).Type.Should().Be(type);
Subject.FindMetadataFile(_movie, path).Type.Should().Be(type);
}
[TestCase(".xml")]
[TestCase(".metathumb")]
public void should_return_null_if_not_valid_file_for_episode(string extension)
public void should_return_null_if_not_valid_file_for_movie(string extension)
{
var path = Path.Combine(_series.Path, "the.series.episode" + extension);
var path = Path.Combine(_movie.Path, "the.movie" + extension);
Subject.FindMetadataFile(_series, path).Should().BeNull();
Subject.FindMetadataFile(_movie, path).Should().BeNull();
}
[Test]
public void should_return_series_image_for_folder_jpg_in_series_folder()
public void should_return_movie_image_for_folder_jpg_in_movie_folder()
{
var path = Path.Combine(_series.Path, "folder.jpg");
var path = Path.Combine(_movie.Path, "folder.jpg");
Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.SeriesImage);
Subject.FindMetadataFile(_movie, path).Type.Should().Be(MetadataType.MovieImage);
}
}
}

View File

@@ -38,8 +38,8 @@ namespace NzbDrone.Core.Test.NetImport
var result = Subject.Fetch();
result.First().Title.Should().Be("Think Like a Man Too");
result.First().ImdbId.Should().Be("tt2239832");
result.Movies.First().Title.Should().Be("Think Like a Man Too");
result.Movies.First().ImdbId.Should().Be("tt2239832");
}
}
}

View File

@@ -84,9 +84,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.11\lib\net40\NLog.dll</HintPath>
<Private>True</Private>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
<HintPath>..\packages\NLog.4.4.12\lib\net40\NLog.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net40\nunit.framework.dll</HintPath>
@@ -283,6 +282,7 @@
<Compile Include="MediaFiles\EpisodeImport\Specifications\MatchesFolderSpecificationFixture.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecificationFixture.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecificationFixture.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameFileSpecificationFixture.cs" />
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecificationFixture.cs" />
<Compile Include="MediaFiles\ImportApprovedEpisodesFixture.cs" />
<Compile Include="MediaFiles\MediaFileRepositoryFixture.cs" />

View File

@@ -10,7 +10,7 @@
<package id="NBuilder" version="4.0.0" targetFramework="net40" />
<package id="NCrunch.Framework" version="1.46.0.9" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.6" targetFramework="net40" />
<package id="NLog" version="4.3.11" targetFramework="net40" />
<package id="NLog" version="4.4.12" targetFramework="net40" />
<package id="NUnit" version="3.5.0" targetFramework="net40" />
<package id="Prowlin" version="0.9.4456.26422" targetFramework="net40" />
<package id="Unity" version="2.1.505.2" targetFramework="net40" />

View File

@@ -4,7 +4,7 @@ namespace NzbDrone.Core.Backup
{
public class Backup
{
public string Path { get; set; }
public string Name { get; set; }
public BackupType Type { get; set; }
public DateTime Time { get; set; }
}

View File

@@ -4,7 +4,18 @@ namespace NzbDrone.Core.Backup
{
public class BackupCommand : Command
{
public BackupType Type { get; set; }
public BackupType Type
{
get
{
if (Trigger == CommandTrigger.Scheduled)
{
return BackupType.Scheduled;
}
return BackupType.Manual;
}
}
public override bool SendUpdatesToClient => true;

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -25,6 +26,7 @@ namespace NzbDrone.Core.Backup
public class BackupService : IBackupService, IExecute<BackupCommand>
{
private readonly IMainDatabase _maindDb;
private readonly IMakeDatabaseBackup _makeDatabaseBackup;
private readonly IDiskTransferService _diskTransferService;
private readonly IDiskProvider _diskProvider;
private readonly IAppFolderInfo _appFolderInfo;
@@ -36,6 +38,7 @@ namespace NzbDrone.Core.Backup
private static readonly Regex BackupFileRegex = new Regex(@"radarr_backup_[._0-9]+\.zip", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public BackupService(IMainDatabase maindDb,
IMakeDatabaseBackup makeDatabaseBackup,
IDiskTransferService diskTransferService,
IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo,
@@ -43,6 +46,7 @@ namespace NzbDrone.Core.Backup
Logger logger)
{
_maindDb = maindDb;
_makeDatabaseBackup = makeDatabaseBackup;
_diskTransferService = diskTransferService;
_diskProvider = diskProvider;
_appFolderInfo = appFolderInfo;
@@ -68,7 +72,7 @@ namespace NzbDrone.Core.Backup
{
CleanupOldBackups(backupType);
}
BackupConfigFile();
BackupDatabase();
@@ -89,7 +93,7 @@ namespace NzbDrone.Core.Backup
{
backups.AddRange(GetBackupFiles(folder).Select(b => new Backup
{
Path = Path.GetFileName(b),
Name = Path.GetFileName(b),
Type = backupType,
Time = _diskProvider.FileGetLastWrite(b)
}));
@@ -111,17 +115,7 @@ namespace NzbDrone.Core.Backup
{
_logger.ProgressDebug("Backing up database");
using (var unitOfWork = new UnitOfWork(() => _maindDb.GetDataMapper()))
{
unitOfWork.BeginTransaction(IsolationLevel.Serializable);
var databaseFile = _appFolderInfo.GetNzbDroneDatabase();
var tempDatabaseFile = Path.Combine(_backupTempFolder, Path.GetFileName(databaseFile));
_diskTransferService.TransferFile(databaseFile, tempDatabaseFile, TransferMode.Copy);
unitOfWork.Commit();
}
_makeDatabaseBackup.BackupDatabase(_maindDb, _backupTempFolder);
}
private void BackupConfigFile()

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