diff --git a/.gitignore b/.gitignore index 8530d0a585..f0e4531073 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,6 @@ packages.config.md5sum **/.idea/**/*.iml **/.idea/**/contentModel.xml **/.idea/**/modules.xml +# ignore node_modules symlink +node_modules +node_modules.nosync diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe2ef5cfd..e8727da573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,43 @@ ## (unreleased) +### **New features** +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Tags support to NetImport (Lists) ([#3127](https://github.com/Radarr/Radarr/issues/3127)) [Ricardo Amaral] +- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Improved templates for h264 & h265 custom formats ([#3432](https://github.com/Radarr/Radarr/issues/3432)) [RhinoRhys] +- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Logo-256.png to a transparent version so it looks better in Android notifications. ([#3479](https://github.com/Radarr/Radarr/issues/3479)) [jwildman16] +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Radarr_Download_Id and Radarr_Download_Client to the environment ([#3276](https://github.com/Radarr/Radarr/issues/3276)) [Logan] +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Allow CheckForFinishedDownloadInterval to be set from the UI ([#3233](https://github.com/Radarr/Radarr/issues/3233)) [Steven Crouchman] +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Added support for Gotify notifications ([#3474](https://github.com/Radarr/Radarr/issues/3474)) [stephanrenggli] +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Remote poster and fanart references to Kodi metadata file ([#2837](https://github.com/Radarr/Radarr/issues/2837)) ([#3302](https://github.com/Radarr/Radarr/issues/3302)) [RobinQ124274] +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Support Krypton Kodi Unique Ids ([#3388](https://github.com/Radarr/Radarr/issues/3388)) [Qstick] +- ![Changed](https://img.shields.io/badge/--%20-Changed-orange.svg?style=flat-square) Adjust Max Slider Value for Qualities ([#3393](https://github.com/Radarr/Radarr/issues/3393)) [Qstick] +- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) README.md ([#3409](https://github.com/Radarr/Radarr/issues/3409)) [hotio] +- ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Nzb Validation and Nzbget/SAB URLBase ([#3380](https://github.com/Radarr/Radarr/issues/3380)) [Qstick] +- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) README.md. [Leonardo Galli] +- ![Updated](https://img.shields.io/badge/--%20-Updated-blue.svg?style=flat-square) docker link in README. [hotio] + +### **Fixes** +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Solve ambiguous naming ([#3417](https://github.com/Radarr/Radarr/issues/3417)) [Viserius] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Copy to clipboard not working with calendar feed ([#3495](https://github.com/Radarr/Radarr/issues/3495)) [Michael Poutre] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Edition Tags Not Showing in UI ([#3389](https://github.com/Radarr/Radarr/issues/3389)) [Qstick] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Support new feed url format IPTorrents ([#573](https://github.com/Radarr/Radarr/issues/573)) ([#3390](https://github.com/Radarr/Radarr/issues/3390)) [Qstick] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCovers Race condition which leads to fanart not being downloaded. [Leonardo Galli] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Cannot Add ITA or ITALIAN custom format ([#3385](https://github.com/Radarr/Radarr/issues/3385)) [Qstick] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OsInfo for real this time. [Leonardo Galli] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Error in unicode cleanup code removing most non-latin characters instead of just invalid ones. ([#3383](https://github.com/Radarr/Radarr/issues/3383)) [Qstick] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Forced Subs not parsed by SubtitleLanguageRegex ([#3384](https://github.com/Radarr/Radarr/issues/3384)) [Qstick] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) OsInfo being renamed to PlatformInfo. [Leonardo Galli] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Word Boundary on Edition ([#3382](https://github.com/Radarr/Radarr/issues/3382)) [Qstick] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Mis-classification of releases as being Czech ([#3378](https://github.com/Radarr/Radarr/issues/3378)) [Václav Slavík] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Match MBluray releases ([#3358](https://github.com/Radarr/Radarr/issues/3358)) [Pieter Janssens] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Mono bug causing memory leakage when http connections use gzip compression. [Leonardo Galli] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Build errors due to dotnet library. [Leonardo Galli] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Emby library update ([#3318](https://github.com/Radarr/Radarr/issues/3318)) [hatharry] +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Prevent NullRef in CustomScript on Grab for Indexer ([#3323](https://github.com/Radarr/Radarr/issues/3323)) [tobsen987] + + +## v0.2.0.1293 (2019-01-10) + ### **New features** - ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Use APIKey & APIUser for authenticating to PassThePopcorn. ([#3264](https://github.com/Radarr/Radarr/issues/3264)) [Leonardo Galli] - ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Support for forcedUP status ([#3277](https://github.com/Radarr/Radarr/issues/3277)) [Swizzy] @@ -10,6 +47,7 @@ - ![New](https://img.shields.io/badge/--%20-New-brightgreen.svg?style=flat-square) Secure URLs for Links and Services ([#3219](https://github.com/Radarr/Radarr/issues/3219)) [Qstick] ### **Fixes** +- ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Hopefully fixed sqlite errors when finding by title. [Leonardo Galli] - ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) Another IDisposable leak when lazy loading properties. [Taloth Saldono] - ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCoverService tests and stupidly forgetting to open the database connection for logging. [Leonardo Galli] - ![Fixed](https://img.shields.io/badge/--%20-Fixed-red.svg?style=flat-square) MediaCovers resizing potentially leaking memory when concurrently executing. [Leonardo Galli] diff --git a/Logo/256.png b/Logo/256.png index acc6bd2957..7ffdc0f991 100644 Binary files a/Logo/256.png and b/Logo/256.png differ diff --git a/package-lock.json b/package-lock.json index b15d259376..05a127061e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -318,6 +318,7 @@ "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "optional": true, "requires": { "hoek": "2.x.x" } @@ -495,6 +496,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "optional": true, "requires": { "delayed-stream": "~1.0.0" } @@ -638,7 +640,8 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "optional": true }, "depd": { "version": "0.4.5", @@ -875,7 +878,8 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "optional": true }, "fancy-log": { "version": "1.3.0", @@ -1061,7 +1065,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.1.1", @@ -1104,7 +1109,8 @@ }, "balanced-match": { "version": "0.4.2", - "bundled": true + "bundled": true, + "optional": true }, "bcrypt-pbkdf": { "version": "1.0.1", @@ -1117,6 +1123,7 @@ "block-stream": { "version": "0.0.9", "bundled": true, + "optional": true, "requires": { "inherits": "~2.0.0" } @@ -1124,6 +1131,7 @@ "boom": { "version": "2.10.1", "bundled": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -1131,6 +1139,7 @@ "brace-expansion": { "version": "1.1.7", "bundled": true, + "optional": true, "requires": { "balanced-match": "^0.4.1", "concat-map": "0.0.1" @@ -1138,7 +1147,8 @@ }, "buffer-shims": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "caseless": { "version": "0.12.0", @@ -1152,30 +1162,36 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "combined-stream": { "version": "1.0.5", "bundled": true, + "optional": true, "requires": { "delayed-stream": "~1.0.0" } }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "cryptiles": { "version": "2.0.5", "bundled": true, + "optional": true, "requires": { "boom": "2.x.x" } @@ -1210,7 +1226,8 @@ }, "delayed-stream": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "delegates": { "version": "1.0.0", @@ -1237,7 +1254,8 @@ }, "extsprintf": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "forever-agent": { "version": "0.6.1", @@ -1256,11 +1274,13 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "fstream": { "version": "1.0.11", "bundled": true, + "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -1311,6 +1331,7 @@ "glob": { "version": "7.1.2", "bundled": true, + "optional": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1322,7 +1343,8 @@ }, "graceful-fs": { "version": "4.1.11", - "bundled": true + "bundled": true, + "optional": true }, "har-schema": { "version": "1.0.5", @@ -1346,6 +1368,7 @@ "hawk": { "version": "3.1.3", "bundled": true, + "optional": true, "requires": { "boom": "2.x.x", "cryptiles": "2.x.x", @@ -1355,7 +1378,8 @@ }, "hoek": { "version": "2.16.3", - "bundled": true + "bundled": true, + "optional": true }, "http-signature": { "version": "1.1.1", @@ -1370,6 +1394,7 @@ "inflight": { "version": "1.0.6", "bundled": true, + "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1377,7 +1402,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.4", @@ -1387,6 +1413,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1398,7 +1425,8 @@ }, "isarray": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "isstream": { "version": "0.1.2", @@ -1461,11 +1489,13 @@ }, "mime-db": { "version": "1.27.0", - "bundled": true + "bundled": true, + "optional": true }, "mime-types": { "version": "2.1.15", "bundled": true, + "optional": true, "requires": { "mime-db": "~1.27.0" } @@ -1473,17 +1503,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -1533,7 +1566,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "oauth-sign": { "version": "0.8.2", @@ -1548,6 +1582,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -1573,7 +1608,8 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "performance-now": { "version": "0.2.0", @@ -1582,7 +1618,8 @@ }, "process-nextick-args": { "version": "1.0.7", - "bundled": true + "bundled": true, + "optional": true }, "punycode": { "version": "1.4.1", @@ -1615,6 +1652,7 @@ "readable-stream": { "version": "2.2.9", "bundled": true, + "optional": true, "requires": { "buffer-shims": "~1.0.0", "core-util-is": "~1.0.0", @@ -1657,13 +1695,15 @@ "rimraf": { "version": "2.6.1", "bundled": true, + "optional": true, "requires": { "glob": "^7.0.5" } }, "safe-buffer": { "version": "5.0.1", - "bundled": true + "bundled": true, + "optional": true }, "semver": { "version": "5.3.0", @@ -1683,6 +1723,7 @@ "sntp": { "version": "1.0.9", "bundled": true, + "optional": true, "requires": { "hoek": "2.x.x" } @@ -1713,6 +1754,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1722,6 +1764,7 @@ "string_decoder": { "version": "1.0.1", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.0.1" } @@ -1734,6 +1777,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1746,6 +1790,7 @@ "tar": { "version": "2.2.1", "bundled": true, + "optional": true, "requires": { "block-stream": "*", "fstream": "^1.0.2", @@ -1795,7 +1840,8 @@ }, "util-deprecate": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "uuid": { "version": "3.0.1", @@ -1820,7 +1866,8 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -2760,7 +2807,8 @@ "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "optional": true }, "homedir-polyfill": { "version": "1.0.1", @@ -3522,12 +3570,14 @@ "mime-db": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", - "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=" + "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=", + "optional": true }, "mime-types": { "version": "2.1.16", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", + "optional": true, "requires": { "mime-db": "~1.29.0" } diff --git a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs index b34febd7b8..4d3a08add2 100644 --- a/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs +++ b/src/NzbDrone.Api/Config/DownloadClientConfigResource.cs @@ -1,4 +1,4 @@ -using NzbDrone.Api.REST; +using NzbDrone.Api.REST; using NzbDrone.Core.Configuration; namespace NzbDrone.Api.Config @@ -11,6 +11,7 @@ public class DownloadClientConfigResource : RestResource public bool EnableCompletedDownloadHandling { get; set; } public bool RemoveCompletedDownloads { get; set; } + public int CheckForFinishedDownloadInterval { get; set; } public bool AutoRedownloadFailed { get; set; } public bool RemoveFailedDownloads { get; set; } @@ -28,6 +29,7 @@ public static DownloadClientConfigResource ToResource(IConfigService model) EnableCompletedDownloadHandling = model.EnableCompletedDownloadHandling, RemoveCompletedDownloads = model.RemoveCompletedDownloads, + CheckForFinishedDownloadInterval = model.CheckForFinishedDownloadInterval, AutoRedownloadFailed = model.AutoRedownloadFailed, RemoveFailedDownloads = model.RemoveFailedDownloads diff --git a/src/NzbDrone.Api/NetImport/NetImportModule.cs b/src/NzbDrone.Api/NetImport/NetImportModule.cs index 042b429d96..a382e51830 100644 --- a/src/NzbDrone.Api/NetImport/NetImportModule.cs +++ b/src/NzbDrone.Api/NetImport/NetImportModule.cs @@ -24,6 +24,7 @@ protected override void MapToResource(NetImportResource resource, NetImportDefin resource.RootFolderPath = definition.RootFolderPath; resource.ShouldMonitor = definition.ShouldMonitor; resource.MinimumAvailability = definition.MinimumAvailability; + resource.Tags = definition.Tags; } protected override void MapToModel(NetImportDefinition definition, NetImportResource resource) @@ -36,6 +37,7 @@ protected override void MapToModel(NetImportDefinition definition, NetImportReso definition.RootFolderPath = resource.RootFolderPath; definition.ShouldMonitor = resource.ShouldMonitor; definition.MinimumAvailability = resource.MinimumAvailability; + definition.Tags = resource.Tags; } protected override void Validate(NetImportDefinition definition, bool includeWarnings) diff --git a/src/NzbDrone.Api/NetImport/NetImportResource.cs b/src/NzbDrone.Api/NetImport/NetImportResource.cs index 360494d400..76716eaa94 100644 --- a/src/NzbDrone.Api/NetImport/NetImportResource.cs +++ b/src/NzbDrone.Api/NetImport/NetImportResource.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using NzbDrone.Core.Movies; namespace NzbDrone.Api.NetImport @@ -10,5 +11,6 @@ public class NetImportResource : ProviderResource public string RootFolderPath { get; set; } public int ProfileId { get; set; } public MovieStatusType MinimumAvailability { get; set; } + public HashSet Tags { get; set; } } } diff --git a/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs b/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs index d846eeee45..63122b53ce 100644 --- a/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs @@ -25,6 +25,8 @@ public void should_normalize_series_title(string parsedSeriesName, string series [TestCase("test/test", "testtest")] [TestCase("90210", "90210")] [TestCase("24", "24")] + [TestCase("I'm a cyborg, but that's OK", "imcyborgbutthatsok")] + [TestCase("Im a cyborg, but thats ok", "imcyborgbutthatsok")] public void should_remove_special_characters_and_casing(string dirty, string clean) { var result = dirty.CleanSeriesTitle(); diff --git a/src/NzbDrone.Core/Configuration/ConfigService.cs b/src/NzbDrone.Core/Configuration/ConfigService.cs index 9b1ca4820f..e107a107a1 100644 --- a/src/NzbDrone.Core/Configuration/ConfigService.cs +++ b/src/NzbDrone.Core/Configuration/ConfigService.cs @@ -273,6 +273,13 @@ public int DownloadedMoviesScanInterval set { SetValue("DownloadedMoviesScanInterval", value); } } + public int CheckForFinishedDownloadInterval + { + get { return GetValueInt("CheckForFinishedDownloadInterval", 1); } + + set { SetValue("CheckForFinishedDownloadInterval", value); } + } + public int DownloadClientHistoryLimit { get { return GetValueInt("DownloadClientHistoryLimit", 30); } diff --git a/src/NzbDrone.Core/Configuration/IConfigService.cs b/src/NzbDrone.Core/Configuration/IConfigService.cs index 790a1a56a6..0b8b2e274c 100644 --- a/src/NzbDrone.Core/Configuration/IConfigService.cs +++ b/src/NzbDrone.Core/Configuration/IConfigService.cs @@ -16,6 +16,7 @@ public interface IConfigService string DownloadClientWorkingFolders { get; set; } int DownloadedMoviesScanInterval { get; set; } int DownloadClientHistoryLimit { get; set; } + int CheckForFinishedDownloadInterval { get; set; } //Completed/Failed Download Handling (Download client) bool EnableCompletedDownloadHandling { get; set; } diff --git a/src/NzbDrone.Core/CustomFormats/CustomFormatService.cs b/src/NzbDrone.Core/CustomFormats/CustomFormatService.cs index 736794192b..0624b4bafc 100644 --- a/src/NzbDrone.Core/CustomFormats/CustomFormatService.cs +++ b/src/NzbDrone.Core/CustomFormats/CustomFormatService.cs @@ -191,8 +191,8 @@ public static Dictionary> Templates { "Easy", new List { - new CustomFormat("x264", "C_RX_(x|h)264"), - new CustomFormat("x265", "C_RX_(((x|h)265)|(HEVC))"), + new CustomFormat("x264", @"C_RX_(x|h)\.?264"), + new CustomFormat("x265", @"C_RX_(((x|h)\.?265)|(HEVC))"), new CustomFormat("Simple Hardcoded Subs", "C_RX_subs?"), new CustomFormat("Multi Language", "L_English", "L_French") } diff --git a/src/NzbDrone.Core/Datastore/Migration/151_add_tags_to_net_import.cs b/src/NzbDrone.Core/Datastore/Migration/151_add_tags_to_net_import.cs new file mode 100644 index 0000000000..69e42c5367 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/151_add_tags_to_net_import.cs @@ -0,0 +1,17 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(151)] + public class add_tags_to_net_import : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("NetImport") + .AddColumn("Tags").AsString().Nullable(); + + Execute.Sql("UPDATE NetImport SET Tags = '[]'"); + } + } +} diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs index 5762c7ee4b..ac82b6df24 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -116,7 +116,9 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil using (var xw = XmlWriter.Create(sb, xws)) { var doc = new XDocument(); - var image = movie.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot); + var thumbnail = movie.Images.SingleOrDefault(i => i.CoverType == MediaCoverTypes.Screenshot); + var posters = movie.Images.Where(i => i.CoverType == MediaCoverTypes.Poster); + var fanarts = movie.Images.Where(i => i.CoverType == MediaCoverTypes.Fanart); var details = new XElement("movie"); @@ -126,7 +128,7 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil { details.Add(new XElement("rating", movie.Ratings.Value)); } - + details.Add(new XElement("plot", movie.Overview)); details.Add(new XElement("id", movie.ImdbId)); @@ -143,7 +145,7 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil details.Add(uniqueId); details.Add(new XElement("year", movie.Year)); - + if (movie.InCinemas.HasValue) { details.Add(new XElement("premiered", movie.InCinemas.Value.ToString("yyyy-MM-dd"))); @@ -156,14 +158,35 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil details.Add(new XElement("studio", movie.Studio)); - if (image == null) + if (thumbnail == null) { details.Add(new XElement("thumb")); } else { - details.Add(new XElement("thumb", image.Url)); + details.Add(new XElement("thumb", thumbnail.Url)); + } + + foreach (var poster in posters) + { + if (poster != null && poster.Url != null) + { + details.Add(new XElement("thumb", new XAttribute("aspect", "poster"), poster.Url)); + } + } + + if (fanarts.Count() > 0) + { + var fanartElement = new XElement("fanart"); + foreach (var fanart in fanarts) + { + if (fanart != null && fanart.Url != null) + { + fanartElement.Add(new XElement("thumb", fanart.Url)); + } + } + details.Add(fanartElement); } details.Add(new XElement("watched", watched)); @@ -215,7 +238,6 @@ public override MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFil xmlResult += doc.ToString(); xmlResult += Environment.NewLine; - } } if (Settings.MovieMetadataURL) diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs index 9b07f83192..f8ead0292a 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupUnusedTags.cs @@ -20,7 +20,7 @@ public void Clean() using (var mapper = _database.GetDataMapper()) { - var usedTags = new[] {"Movies", "Notifications", "DelayProfiles", "Restrictions"} + var usedTags = new[] {"Movies", "Notifications", "DelayProfiles", "Restrictions", "NetImport"} .SelectMany(v => GetUsedTags(v, mapper)) .Distinct() .ToArray(); diff --git a/src/NzbDrone.Core/Jobs/TaskManager.cs b/src/NzbDrone.Core/Jobs/TaskManager.cs index 7133803ca7..e8e0ce4dcb 100644 --- a/src/NzbDrone.Core/Jobs/TaskManager.cs +++ b/src/NzbDrone.Core/Jobs/TaskManager.cs @@ -71,7 +71,6 @@ public void Handle(ApplicationStartedEvent message) var defaultTasks = new[] { - new ScheduledTask{ Interval = 1, TypeName = typeof(CheckForFinishedDownloadCommand).FullName}, new ScheduledTask{ Interval = 1*60, TypeName = typeof(PreDBSyncCommand).FullName}, new ScheduledTask{ Interval = 5, TypeName = typeof(MessagingCleanupCommand).FullName}, new ScheduledTask{ Interval = updateInterval, TypeName = typeof(ApplicationUpdateCommand).FullName}, @@ -98,6 +97,12 @@ public void Handle(ApplicationStartedEvent message) Interval = _configService.DownloadedMoviesScanInterval, TypeName = typeof(DownloadedMoviesScanCommand).FullName }, + + new ScheduledTask + { + Interval = Math.Max(_configService.CheckForFinishedDownloadInterval, 1), + TypeName = typeof(CheckForFinishedDownloadCommand).FullName + }, }; var currentTasks = _scheduledTaskRepository.All().ToList(); @@ -184,7 +189,10 @@ public void HandleAsync(ConfigSavedEvent message) var netImport = _scheduledTaskRepository.GetDefinition(typeof(NetImportSyncCommand)); netImport.Interval = _configService.NetImportSyncInterval; - _scheduledTaskRepository.UpdateMany(new List { rss, downloadedMovies, netImport }); + var checkForFinishedDownloads = _scheduledTaskRepository.GetDefinition(typeof(CheckForFinishedDownloadCommand)); + checkForFinishedDownloads.Interval = _configService.CheckForFinishedDownloadInterval; + + _scheduledTaskRepository.UpdateMany(new List { rss, downloadedMovies, netImport, checkForFinishedDownloads }); } } } diff --git a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs index 89df9fc5cc..e13d75eed1 100644 --- a/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/SkyHook/SkyHookProxy.cs @@ -701,6 +701,7 @@ public Movie MapMovieToTmdbMovie(Movie movie) newMovie.Monitored = movie.Monitored; newMovie.MovieFile = movie.MovieFile; newMovie.MinimumAvailability = movie.MinimumAvailability; + newMovie.Tags = movie.Tags; return newMovie; } diff --git a/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs b/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs index 92e53b994e..7564c448ee 100644 --- a/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs +++ b/src/NzbDrone.Core/NetImport/HttpNetImportBase.cs @@ -118,6 +118,7 @@ protected virtual IList FetchPage(NetImportRequest request, IParseNetImpo m.ProfileId = ((NetImportDefinition) Definition).ProfileId; m.Monitored = ((NetImportDefinition) Definition).ShouldMonitor; m.MinimumAvailability = ((NetImportDefinition) Definition).MinimumAvailability; + m.Tags = ((NetImportDefinition) Definition).Tags; return m; }).ToList(); } @@ -170,6 +171,5 @@ protected virtual ValidationFailure TestConnection() return null; } } - } diff --git a/src/NzbDrone.Core/NetImport/NetImportDefinition.cs b/src/NzbDrone.Core/NetImport/NetImportDefinition.cs index 6462fb008b..176db1773f 100644 --- a/src/NzbDrone.Core/NetImport/NetImportDefinition.cs +++ b/src/NzbDrone.Core/NetImport/NetImportDefinition.cs @@ -1,4 +1,5 @@ -using Marr.Data; +using System.Collections.Generic; +using Marr.Data; using NzbDrone.Core.Profiles; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Movies; @@ -7,6 +8,11 @@ namespace NzbDrone.Core.NetImport { public class NetImportDefinition : ProviderDefinition { + public NetImportDefinition() + { + Tags = new HashSet(); + } + public bool Enabled { get; set; } public bool EnableAuto { get; set; } public bool ShouldMonitor { get; set; } @@ -15,5 +21,6 @@ public class NetImportDefinition : ProviderDefinition public LazyLoaded Profile { get; set; } public string RootFolderPath { get; set; } public override bool Enable => Enabled; + public HashSet Tags { get; set; } } } diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs index 9305c87eab..203559c143 100755 --- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs +++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs @@ -46,6 +46,8 @@ public override void OnGrab(GrabMessage message) environmentVariables.Add("Radarr_Release_Quality", quality.Quality.Name); environmentVariables.Add("Radarr_Release_QualityVersion", quality.Revision.Version.ToString()); environmentVariables.Add("Radarr_IndexerFlags", remoteMovie.Release.IndexerFlags.ToString()); + environmentVariables.Add("Radarr_Download_Client", message.DownloadClient ?? string.Empty); + environmentVariables.Add("Radarr_Download_Id", message.DownloadId ?? string.Empty); ExecuteScript(environmentVariables); } diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs new file mode 100644 index 0000000000..63ffadd92d --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using FluentValidation.Results; +using NLog; +using NzbDrone.Core.Movies; + +namespace NzbDrone.Core.Notifications.Gotify +{ + public class Gotify : NotificationBase + { + private readonly IGotifyProxy _proxy; + private readonly Logger _logger; + + public Gotify(IGotifyProxy proxy, Logger logger) + { + _proxy = proxy; + _logger = logger; + } + + public override string Name => "Gotify"; + public override string Link => "https://gotify.net/"; + + public override void OnGrab(GrabMessage grabMessage) + { + const string title = "Movie Grabbed"; + + _proxy.SendNotification(title, grabMessage.Message, Settings); + } + + public override void OnDownload(DownloadMessage message) + { + const string title = "Movie Downloaded"; + + _proxy.SendNotification(title, message.Message, Settings); + } + + public override void OnMovieRename(Movie movie) + { + } + + public override bool SupportsOnRename => false; + + public override ValidationResult Test() + { + var failures = new List(); + + try + { + const string title = "Test Notification"; + const string body = "This is a test message from Radarr"; + + _proxy.SendNotification(title, body, Settings); + } + catch (Exception ex) + { + _logger.Error(ex, "Unable to send test message"); + failures.Add(new ValidationFailure("", "Unable to send test message")); + } + + return new ValidationResult(failures); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifyPriority.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifyPriority.cs new file mode 100644 index 0000000000..9a5f9c5dcf --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifyPriority.cs @@ -0,0 +1,10 @@ +namespace NzbDrone.Core.Notifications.Gotify +{ + public enum GotifyPriority + { + Min = 0, + Low = 2, + Normal = 5, + High = 8 + } +} diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifyService.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifyService.cs new file mode 100644 index 0000000000..b14b530d39 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifyService.cs @@ -0,0 +1,26 @@ +using RestSharp; +using NzbDrone.Core.Rest; + +namespace NzbDrone.Core.Notifications.Gotify +{ + public interface IGotifyProxy + { + void SendNotification(string title, string message, GotifySettings settings); + } + + public class GotifyProxy : IGotifyProxy + { + public void SendNotification(string title, string message, GotifySettings settings) + { + var client = RestClientFactory.BuildClient(settings.Server); + var request = new RestRequest("message", Method.POST); + + request.AddQueryParameter("token", settings.AppToken); + request.AddParameter("title", title); + request.AddParameter("message", message); + request.AddParameter("priority", settings.Priority); + + client.ExecuteAndValidate(request); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs new file mode 100644 index 0000000000..4e6f929c99 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs @@ -0,0 +1,40 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Notifications.Gotify +{ + public class GotifySettingsValidator : AbstractValidator + { + public GotifySettingsValidator() + { + RuleFor(c => c.Server).IsValidUrl(); + RuleFor(c => c.AppToken).NotEmpty(); + } + } + + public class GotifySettings : IProviderConfig + { + private static readonly GotifySettingsValidator Validator = new GotifySettingsValidator(); + + public GotifySettings() + { + Priority = 5; + } + + [FieldDefinition(0, Label = "Gotify Server", HelpText = "Gotify server URL, including http(s):// and port if needed")] + public string Server { get; set; } + + [FieldDefinition(1, Label = "App Token", HelpText = "The Application Token generated by Gotify")] + public string AppToken { get; set; } + + [FieldDefinition(2, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(GotifyPriority), HelpText = "Priority of the notification")] + public int Priority { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Gotify/InvalidResponseException.cs b/src/NzbDrone.Core/Notifications/Gotify/InvalidResponseException.cs new file mode 100644 index 0000000000..0a4c20b4dd --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Gotify/InvalidResponseException.cs @@ -0,0 +1,15 @@ +using System; + +namespace NzbDrone.Core.Notifications.Gotify +{ + public class InvalidResponseException : Exception + { + public InvalidResponseException() + { + } + + public InvalidResponseException(string message) : base(message) + { + } + } +} diff --git a/src/NzbDrone.Core/Notifications/GrabMessage.cs b/src/NzbDrone.Core/Notifications/GrabMessage.cs index 25c34dac7d..ecc25c4f17 100644 --- a/src/NzbDrone.Core/Notifications/GrabMessage.cs +++ b/src/NzbDrone.Core/Notifications/GrabMessage.cs @@ -1,4 +1,4 @@ -using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Movies; @@ -9,7 +9,9 @@ public class GrabMessage public string Message { get; set; } public Movie Movie { get; set; } public RemoteMovie RemoteMovie { get; set; } - public QualityModel Quality { get; set; } + public QualityModel Quality { get; set; } + public string DownloadClient { get; set; } + public string DownloadId { get; set; } public override string ToString() { diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index 91b323715f..2809bcac7b 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -72,7 +72,9 @@ public void Handle(MovieGrabbedEvent message) Message = GetMessage(message.Movie.Movie, message.Movie.ParsedMovieInfo.Quality), Quality = message.Movie.ParsedMovieInfo.Quality, Movie = message.Movie.Movie, - RemoteMovie = message.Movie + RemoteMovie = message.Movie, + DownloadClient = message.DownloadClient, + DownloadId = message.DownloadId }; foreach (var notification in _notificationFactory.OnGrabEnabled()) diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index bf24d10b24..a22017c034 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -146,6 +146,7 @@ + @@ -925,6 +926,11 @@ + + + + + @@ -1330,4 +1336,4 @@ --> - \ No newline at end of file + diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index c6b2695fca..4b9a340bb4 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -90,7 +90,7 @@ public static class Parser //Regex to detect whether the title was reversed. private static readonly Regex ReversedTitleRegex = new Regex(@"(?:^|[-._ ])(p027|p0801)[-._ ]", RegexOptions.Compiled); - private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(? + +
+ + +
+ +
+ +
+ +
+
diff --git a/src/UI/Settings/General/GeneralView.js b/src/UI/Settings/General/GeneralView.js index 81f638f347..e027ea8302 100644 --- a/src/UI/Settings/General/GeneralView.js +++ b/src/UI/Settings/General/GeneralView.js @@ -4,8 +4,6 @@ var CommandController = require('../../Commands/CommandController'); var AsModelBoundView = require('../../Mixins/AsModelBoundView'); var AsValidatedView = require('../../Mixins/AsValidatedView'); -require('../../Mixins/CopyToClipboard'); - var view = Marionette.ItemView.extend({ template : 'Settings/General/GeneralViewTemplate', @@ -14,6 +12,7 @@ var view = Marionette.ItemView.extend({ 'change .x-proxy' : '_setProxyOptionsVisibility', 'change .x-ssl' : '_setSslOptionsVisibility', 'click .x-reset-api-key' : '_resetApiKey', + 'click .x-copy-api-key' : '_copyApiKeyToClipboard', 'change .x-update-mechanism' : '_setScriptGroupVisibility' }, @@ -57,11 +56,12 @@ var view = Marionette.ItemView.extend({ command : { name : 'resetApiKey' } - }); + }); }, - - onShow : function() { - this.ui.copyApiKey.copyToClipboard(this.ui.apiKeyInput); + + _copyApiKeyToClipboard : function() { + this.ui.apiKeyInput.select(); + document.execCommand("copy"); }, _setAuthOptionsVisibility : function() { diff --git a/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs b/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs index a0bbafc8f3..ef15d292b9 100644 --- a/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs +++ b/src/UI/Settings/MediaManagement/FileManagement/FileManagementViewTemplate.hbs @@ -2,7 +2,7 @@ File Management
- +
diff --git a/src/UI/Settings/NetImport/Edit/NetImportEditView.js b/src/UI/Settings/NetImport/Edit/NetImportEditView.js index 8d31ef6935..a407ef2d47 100644 --- a/src/UI/Settings/NetImport/Edit/NetImportEditView.js +++ b/src/UI/Settings/NetImport/Edit/NetImportEditView.js @@ -22,6 +22,7 @@ var view = Marionette.ItemView.extend({ profile : '.x-profile', minimumAvailability : '.x-minimumavailability', rootFolder : '.x-root-folder', + tags : '.x-tags' }, events : { @@ -53,6 +54,10 @@ var view = Marionette.ItemView.extend({ this.ui.rootFolder.val(defaultRoot); } } + this.ui.tags.tagInput({ + model : this.model, + property : 'tags' + }); }, _onBeforeSave : function() { diff --git a/src/UI/Settings/NetImport/Edit/NetImportEditViewTemplate.hbs b/src/UI/Settings/NetImport/Edit/NetImportEditViewTemplate.hbs index 46fd5292fb..89349fd169 100644 --- a/src/UI/Settings/NetImport/Edit/NetImportEditViewTemplate.hbs +++ b/src/UI/Settings/NetImport/Edit/NetImportEditViewTemplate.hbs @@ -101,6 +101,14 @@
+
+ + +
+ +
+
+ {{formBuilder}}
diff --git a/src/UI/app.js b/src/UI/app.js index 3ebfafdb07..7746da259a 100644 --- a/src/UI/app.js +++ b/src/UI/app.js @@ -29,7 +29,6 @@ require.config({ 'messenger' : 'JsLibraries/messenger', 'jquery' : 'JsLibraries/jquery', 'typeahead' : 'JsLibraries/typeahead', - 'zero.clipboard' : 'JsLibraries/zero.clipboard', 'libs' : 'JsLibraries/' }, diff --git a/src/UI/vendor.js b/src/UI/vendor.js index dc343bb357..19892f40cb 100644 --- a/src/UI/vendor.js +++ b/src/UI/vendor.js @@ -11,7 +11,6 @@ require('jquery.knob'); require('jquery.easypiechart'); require('jquery.dotdotdot'); require('typeahead'); -require('zero.clipboard'); /*Bootstrap*/ require('bootstrap');