From c79578e99f45c1557abfe61b0b5f59597d3fb018 Mon Sep 17 00:00:00 2001 From: RobinQ124274 <40181407+RobinQ124274@users.noreply.github.com> Date: Sun, 28 Apr 2019 01:33:06 +0200 Subject: [PATCH 01/11] Added: Remote poster and fanart references to Kodi metadata file (#2837) (#3302) * Added: Remote poster and fanart references to Kodi metadata file (#2837) * Added: Null checks to Remote poster and fanart references to Kodi metadata file (#2837) --- .../Metadata/Consumers/Xbmc/XbmcMetadata.cs | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs index 9ae6b58a0b..ce4af082e9 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; @@ -121,7 +121,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"); @@ -161,14 +163,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)); From da012eb6b541923e6af02de5f4b49adc5d5c96ad Mon Sep 17 00:00:00 2001 From: Michael Poutre Date: Thu, 2 May 2019 03:38:00 -0700 Subject: [PATCH 02/11] Fixed: Copy to clipboard not working with calendar feed (#3495) * Replace flash clipboard implementation with document.execute("copy") Fixes #3486 * Replace flash clipboard implementation with document.execCommand("copy") Resolves Radarr/Radarr#3486 --- .gitignore | 3 + package-lock.json | 102 ++++++++++++++++++------- src/UI/Calendar/CalendarFeedView.js | 8 +- src/UI/Mixins/CopyToClipboard.js | 22 ------ src/UI/Settings/General/GeneralView.js | 12 +-- src/UI/app.js | 1 - src/UI/vendor.js | 1 - 7 files changed, 91 insertions(+), 58 deletions(-) delete mode 100644 src/UI/Mixins/CopyToClipboard.js 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/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/UI/Calendar/CalendarFeedView.js b/src/UI/Calendar/CalendarFeedView.js index 861e68cc0c..c167ce89f9 100644 --- a/src/UI/Calendar/CalendarFeedView.js +++ b/src/UI/Calendar/CalendarFeedView.js @@ -1,6 +1,5 @@ var Marionette = require('marionette'); var StatusModel = require('../System/StatusModel'); -require('../Mixins/CopyToClipboard'); require('../Mixins/TagInput'); module.exports = Marionette.Layout.extend({ @@ -18,16 +17,21 @@ module.exports = Marionette.Layout.extend({ events : { 'click .x-includeUnmonitored' : '_updateUrl', 'click .x-premiersOnly' : '_updateUrl', + 'click .x-ical-copy' : '_copyIcalToClipboard', 'itemAdded .x-tags' : '_updateUrl', 'itemRemoved .x-tags' : '_updateUrl' }, onShow : function() { this._updateUrl(); - this.ui.icalCopy.copyToClipboard(this.ui.icalUrl); this.ui.tags.tagInput({ allowNew: false }); }, + _copyIcalToClipboard: function () { + this.ui.icalUrl.select(); + document.execCommand("copy"); + }, + _updateUrl : function() { var icalUrl = window.location.host + StatusModel.get('urlBase') + '/feed/calendar/Radarr.ics?'; diff --git a/src/UI/Mixins/CopyToClipboard.js b/src/UI/Mixins/CopyToClipboard.js deleted file mode 100644 index 77db6e39a4..0000000000 --- a/src/UI/Mixins/CopyToClipboard.js +++ /dev/null @@ -1,22 +0,0 @@ -var $ = require('jquery'); -var StatusModel = require('../System/StatusModel'); -var ZeroClipboard = require('zero.clipboard'); -var Messenger = require('../Shared/Messenger'); - -$.fn.copyToClipboard = function(input) { - - ZeroClipboard.config({ - swfPath : StatusModel.get('urlBase') + '/Content/zero.clipboard.swf' - }); - - var client = new ZeroClipboard(this); - - client.on('ready', function(e) { - client.on('copy', function(e) { - e.clipboardData.setData("text/plain", input.val()); - }); - client.on('aftercopy', function() { - Messenger.show({ message : 'Copied text to clipboard' }); - }); - }); -}; \ No newline at end of file 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/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'); From f8c009a348a8b5cd2482620d6c3459a305e30f48 Mon Sep 17 00:00:00 2001 From: Viserius Date: Thu, 2 May 2019 12:40:51 +0200 Subject: [PATCH 03/11] Fixed: Solve ambiguous naming (#3417) --- .../FileManagement/FileManagementViewTemplate.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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
- +
From 9985554dcb4b3877bea008bcf38294bd1a7fe9fc Mon Sep 17 00:00:00 2001 From: stephanrenggli <5135902+stephanrenggli@users.noreply.github.com> Date: Thu, 2 May 2019 12:49:21 +0200 Subject: [PATCH 04/11] New: Added support for Gotify notifications (#3474) * Added support for Gotify notifications * Use string interpolation to build url * Adapt changes by markus101 over at Sonarr * Remove blank line Fixes #3472 --- .../Notifications/Gotify/Gotify.cs | 63 +++++++++++++++++++ .../Notifications/Gotify/GotifyPriority.cs | 10 +++ .../Notifications/Gotify/GotifyService.cs | 26 ++++++++ .../Notifications/Gotify/GotifySettings.cs | 40 ++++++++++++ .../Gotify/InvalidResponseException.cs | 15 +++++ src/NzbDrone.Core/NzbDrone.Core.csproj | 5 ++ 6 files changed, 159 insertions(+) create mode 100644 src/NzbDrone.Core/Notifications/Gotify/Gotify.cs create mode 100644 src/NzbDrone.Core/Notifications/Gotify/GotifyPriority.cs create mode 100644 src/NzbDrone.Core/Notifications/Gotify/GotifyService.cs create mode 100644 src/NzbDrone.Core/Notifications/Gotify/GotifySettings.cs create mode 100644 src/NzbDrone.Core/Notifications/Gotify/InvalidResponseException.cs 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/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index bf24d10b24..90f2ded6c2 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -925,6 +925,11 @@ + + + + + From f411903e90224c976f0b7e61406450374c19e408 Mon Sep 17 00:00:00 2001 From: Steven Crouchman Date: Thu, 2 May 2019 11:51:21 +0100 Subject: [PATCH 05/11] New: Allow CheckForFinishedDownloadInterval to be set from the UI (#3233) * Adding CheckForFinishedDownloadInterval to config service Changed TaskManager to use a configurable interval for CheckForFinishedDownloadCommand * Adding new CheckForFinishedDownloadInterval to UI Fixes #840 --- .../Config/DownloadClientConfigResource.cs | 4 +++- src/NzbDrone.Core/Configuration/ConfigService.cs | 7 +++++++ src/NzbDrone.Core/Configuration/IConfigService.cs | 1 + src/NzbDrone.Core/Jobs/TaskManager.cs | 12 ++++++++++-- .../DownloadHandlingViewTemplate.hbs | 12 ++++++++++++ 5 files changed, 33 insertions(+), 3 deletions(-) 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.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/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/UI/Settings/DownloadClient/DownloadHandling/DownloadHandlingViewTemplate.hbs b/src/UI/Settings/DownloadClient/DownloadHandling/DownloadHandlingViewTemplate.hbs index b268197f99..43352b946f 100644 --- a/src/UI/Settings/DownloadClient/DownloadHandling/DownloadHandlingViewTemplate.hbs +++ b/src/UI/Settings/DownloadClient/DownloadHandling/DownloadHandlingViewTemplate.hbs @@ -43,6 +43,18 @@
+ +
+ + +
+ +
+ +
+ +
+
From cc44d022b34c8e5f88ef5cdc48883ed30a786cf6 Mon Sep 17 00:00:00 2001 From: Logan Date: Thu, 2 May 2019 06:52:33 -0400 Subject: [PATCH 06/11] Added: Radarr_Download_Id and Radarr_Download_Client to the environment (#3276) Fixes #3232 --- .../Notifications/CustomScript/CustomScript.cs | 2 ++ src/NzbDrone.Core/Notifications/GrabMessage.cs | 6 ++++-- src/NzbDrone.Core/Notifications/NotificationService.cs | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) 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/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()) From 52520e356d9cca597337b19d4c201f654f74981e Mon Sep 17 00:00:00 2001 From: jwildman16 Date: Thu, 2 May 2019 04:55:01 -0600 Subject: [PATCH 07/11] Changed: Logo-256.png to a transparent version so it looks better in Android notifications. (#3479) --- Logo/256.png | Bin 10424 -> 28752 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Logo/256.png b/Logo/256.png index acc6bd2957724e74b4b41732b84542c23dfff47b..7ffdc0f991af1445ae72825caccbf9c4b0dd4ac4 100644 GIT binary patch literal 28752 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

aE#ikOJnaQ+`;%E9i7pEFZlh%cZT2Q=CHG{ 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 fqpy-STO3}^dWUKMWnb(W?8 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 P`xT(2rmxzd>=6AwrkrFT From 84fab25af7b16cd94af8f0713f2f032f57b1cbbf Mon Sep 17 00:00:00 2001 From: RhinoRhys <41245810+RhinoRhys@users.noreply.github.com> Date: Thu, 2 May 2019 11:55:48 +0100 Subject: [PATCH 08/11] Changed: Improved templates for h264 & h265 custom formats (#3432) * Update CustomFormatService.cs resolves #3419 * Update CustomFormatService.cs * Update CustomFormatService.cs --- src/NzbDrone.Core/CustomFormats/CustomFormatService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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") } From 7a43bf3f6072db8ddb0d0b1adf60c136237b0e51 Mon Sep 17 00:00:00 2001 From: Ricardo Amaral Date: Thu, 2 May 2019 11:57:40 +0100 Subject: [PATCH 09/11] Added: Tags support to NetImport (Lists) (#3127) * Add tags support to NetImport (Lists) * Keep indentation consistent with current code * Initialize set of empty tags * Add tags from list to movie * Prevent tags used by lists from being removed --- src/NzbDrone.Api/NetImport/NetImportModule.cs | 2 ++ src/NzbDrone.Api/NetImport/NetImportResource.cs | 2 ++ .../Migration/151_add_tags_to_net_import.cs | 17 +++++++++++++++++ .../Housekeepers/CleanupUnusedTags.cs | 2 +- .../MetadataSource/SkyHook/SkyHookProxy.cs | 1 + .../NetImport/HttpNetImportBase.cs | 2 +- .../NetImport/NetImportDefinition.cs | 9 ++++++++- src/NzbDrone.Core/NzbDrone.Core.csproj | 3 ++- .../NetImport/Edit/NetImportEditView.js | 5 +++++ .../Edit/NetImportEditViewTemplate.hbs | 8 ++++++++ 10 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/151_add_tags_to_net_import.cs 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/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/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/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/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 90f2ded6c2..a22017c034 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -146,6 +146,7 @@ + @@ -1335,4 +1336,4 @@ --> - \ No newline at end of file + 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}} From 5faaffc9c6a48e5a8bf6c04b2ec48370af6bd1ab Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Thu, 2 May 2019 13:05:35 +0200 Subject: [PATCH 10/11] @cosmetic updated changelog --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) 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] From 7756b03555c836e5a6a7dc9ead18e9552898241c Mon Sep 17 00:00:00 2001 From: Leonardo Galli Date: Thu, 2 May 2019 13:18:28 +0200 Subject: [PATCH 11/11] Fixed: a after a shortened word is not removed correctly for matching. Fixes ##3487 --- src/NzbDrone.Core.Test/ParserTests/NormalizeTitleFixture.cs | 2 ++ src/NzbDrone.Core/Parser/Parser.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) 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/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|_)(?