mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-27 17:54:34 -04:00
Compare commits
9 Commits
v2.0.0.440
...
v2.0.0.442
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c99e92e6af | ||
|
|
3f64c01d5b | ||
|
|
f022dae1fa | ||
|
|
52ad8cf37f | ||
|
|
3d20fd8f96 | ||
|
|
cf662291d5 | ||
|
|
43d85bf59d | ||
|
|
4a149c356b | ||
|
|
740fc9154f |
@@ -48,11 +48,11 @@
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Org.Mentalis, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DotNet4.SocksProxy.1.1.0.0\lib\net40\Org.Mentalis.dll</HintPath>
|
||||
<HintPath>..\packages\DotNet4.SocksProxy.1.3.2.0\lib\net40\Org.Mentalis.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SocksWebProxy, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DotNet4.SocksProxy.1.1.0.0\lib\net40\SocksWebProxy.dll</HintPath>
|
||||
<Reference Include="SocksWebProxy, Version=1.3.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DotNet4.SocksProxy.1.3.2.0\lib\net40\SocksWebProxy.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="DotNet4.SocksProxy" version="1.1.0.0" targetFramework="net40" />
|
||||
<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.4" targetFramework="net40" />
|
||||
|
||||
@@ -17,12 +17,13 @@ namespace NzbDrone.Core.Notifications.Plex.Models
|
||||
public string Type { get; set; }
|
||||
public string Language { get; set; }
|
||||
|
||||
public PlexSectionLocation Location { get; set; }
|
||||
[JsonProperty("Location")]
|
||||
public List<PlexSectionLocation> Locations { get; set; }
|
||||
}
|
||||
|
||||
public class PlexSectionsContainer
|
||||
{
|
||||
[JsonProperty("Metadata")]
|
||||
[JsonProperty("Directory")]
|
||||
public List<PlexSection> Sections { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace NzbDrone.Core.Notifications.Plex.Models
|
||||
|
||||
public class PlexSectionResponse
|
||||
{
|
||||
[JsonProperty("Metadata")]
|
||||
public List<PlexSectionItem> Items { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
{
|
||||
Id = s.Id,
|
||||
Language = s.Language,
|
||||
Location = s.Locations.FirstOrDefault(),
|
||||
Locations = s.Locations,
|
||||
Type = s.Type
|
||||
})
|
||||
.ToList();
|
||||
@@ -97,12 +97,15 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
_logger.Trace("Version response: {0}", response.Content);
|
||||
CheckForError(response, settings);
|
||||
|
||||
if (response.Content.Contains("MediaContainer"))
|
||||
if (response.Content.Contains("_children"))
|
||||
{
|
||||
return Json.Deserialize<PlexResponse<PlexIdentity>>(response.Content).MediaContainer.Version;
|
||||
return Json.Deserialize<PlexIdentity>(response.Content)
|
||||
.Version;
|
||||
}
|
||||
|
||||
return Json.Deserialize<PlexIdentity>(response.Content).Version;
|
||||
return Json.Deserialize<PlexResponse<PlexIdentity>>(response.Content)
|
||||
.MediaContainer
|
||||
.Version;
|
||||
}
|
||||
|
||||
public List<PlexPreference> Preferences(PlexServerSettings settings)
|
||||
@@ -114,12 +117,15 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
_logger.Trace("Preferences response: {0}", response.Content);
|
||||
CheckForError(response, settings);
|
||||
|
||||
if (response.Content.Contains("MediaContainer"))
|
||||
if (response.Content.Contains("_children"))
|
||||
{
|
||||
return Json.Deserialize<PlexResponse<PlexPreferences>>(response.Content).MediaContainer.Preferences;
|
||||
return Json.Deserialize<PlexPreferencesLegacy>(response.Content)
|
||||
.Preferences;
|
||||
}
|
||||
|
||||
return Json.Deserialize<PlexPreferencesLegacy>(response.Content).Preferences;
|
||||
return Json.Deserialize<PlexResponse<PlexPreferences>>(response.Content)
|
||||
.MediaContainer
|
||||
.Preferences;
|
||||
}
|
||||
|
||||
public int? GetMetadataId(int sectionId, int tvdbId, string language, PlexServerSettings settings)
|
||||
@@ -143,7 +149,8 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
|
||||
else
|
||||
{
|
||||
items = Json.Deserialize<PlexSectionResponse>(response.Content)
|
||||
items = Json.Deserialize<PlexResponse<PlexSectionResponse>>(response.Content)
|
||||
.MediaContainer
|
||||
.Items;
|
||||
}
|
||||
|
||||
@@ -240,9 +247,15 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
throw new PlexAuthenticationException("Unauthorized - Username or password is incorrect");
|
||||
}
|
||||
|
||||
var error = response.Content.Contains("MediaContainer") ?
|
||||
Json.Deserialize<PlexResponse<PlexError>>(response.Content).MediaContainer :
|
||||
Json.Deserialize<PlexError>(response.Content);
|
||||
if (response.Content.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Trace("No response body returned, no error detected");
|
||||
return;
|
||||
}
|
||||
|
||||
var error = response.Content.Contains("_children") ?
|
||||
Json.Deserialize<PlexError>(response.Content) :
|
||||
Json.Deserialize<PlexResponse<PlexError>>(response.Content).MediaContainer;
|
||||
|
||||
if (error != null && !error.Error.IsNullOrWhiteSpace())
|
||||
{
|
||||
|
||||
@@ -19,12 +19,14 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
|
||||
public class PlexServerService : IPlexServerService
|
||||
{
|
||||
private readonly ICached<Version> _versionCache;
|
||||
private readonly ICached<bool> _partialUpdateCache;
|
||||
private readonly IPlexServerProxy _plexServerProxy;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public PlexServerService(ICacheManager cacheManager, IPlexServerProxy plexServerProxy, Logger logger)
|
||||
{
|
||||
_versionCache = cacheManager.GetCache<Version>(GetType(), "versionCache");
|
||||
_partialUpdateCache = cacheManager.GetCache<bool>(GetType(), "partialUpdateCache");
|
||||
_plexServerProxy = plexServerProxy;
|
||||
_logger = logger;
|
||||
@@ -35,9 +37,12 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
try
|
||||
{
|
||||
_logger.Debug("Sending Update Request to Plex Server");
|
||||
|
||||
|
||||
var version = _versionCache.Get(settings.Host, () => GetVersion(settings), TimeSpan.FromHours(2));
|
||||
ValidateVersion(version);
|
||||
|
||||
var sections = GetSections(settings);
|
||||
var partialUpdates = _partialUpdateCache.Get(settings.Host, () => PartialUpdatesAllowed(settings), TimeSpan.FromHours(2));
|
||||
var partialUpdates = _partialUpdateCache.Get(settings.Host, () => PartialUpdatesAllowed(settings, version), TimeSpan.FromHours(2));
|
||||
|
||||
if (partialUpdates)
|
||||
{
|
||||
@@ -64,13 +69,10 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
return _plexServerProxy.GetTvSections(settings).ToList();
|
||||
}
|
||||
|
||||
private bool PartialUpdatesAllowed(PlexServerSettings settings)
|
||||
private bool PartialUpdatesAllowed(PlexServerSettings settings, Version version)
|
||||
{
|
||||
try
|
||||
{
|
||||
var rawVersion = GetVersion(settings);
|
||||
var version = new Version(Regex.Match(rawVersion, @"^(\d+[.-]){4}").Value.Trim('.', '-'));
|
||||
|
||||
if (version >= new Version(0, 9, 12, 0))
|
||||
{
|
||||
var preferences = GetPreferences(settings);
|
||||
@@ -92,13 +94,28 @@ namespace NzbDrone.Core.Notifications.Plex
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetVersion(PlexServerSettings settings)
|
||||
private void ValidateVersion(Version version)
|
||||
{
|
||||
if (version >= new Version(1, 3, 0) && version < new Version(1, 3, 1))
|
||||
{
|
||||
throw new PlexVersionException("Found version {0}, upgrade to PMS 1.3.1 to fix library updating and then restart Sonarr", version);
|
||||
}
|
||||
}
|
||||
|
||||
private Version GetVersion(PlexServerSettings settings)
|
||||
{
|
||||
_logger.Debug("Getting version from Plex host: {0}", settings.Host);
|
||||
|
||||
return _plexServerProxy.Version(settings);
|
||||
var rawVersion = _plexServerProxy.Version(settings);
|
||||
var version = new Version(Regex.Match(rawVersion, @"^(\d+[.-]){4}").Value.Trim('.', '-'));
|
||||
|
||||
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<PlexPreference> GetPreferences(PlexServerSettings settings)
|
||||
{
|
||||
_logger.Debug("Getting preferences from Plex host: {0}", settings.Host);
|
||||
|
||||
15
src/NzbDrone.Core/Notifications/Plex/PlexVersionException.cs
Normal file
15
src/NzbDrone.Core/Notifications/Plex/PlexVersionException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using NzbDrone.Common.Exceptions;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Plex
|
||||
{
|
||||
public class PlexVersionException : NzbDroneException
|
||||
{
|
||||
public PlexVersionException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public PlexVersionException(string message, params object[] args) : base(message, args)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Telegram
|
||||
{
|
||||
public class InvalidResponseException : Exception
|
||||
{
|
||||
public InvalidResponseException()
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidResponseException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/NzbDrone.Core/Notifications/Telegram/Telegram.cs
Normal file
65
src/NzbDrone.Core/Notifications/Telegram/Telegram.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Telegram
|
||||
{
|
||||
public class Telegram : NotificationBase<TelegramSettings>
|
||||
{
|
||||
private readonly ITelegramProxy _proxy;
|
||||
|
||||
public Telegram(ITelegramProxy proxy)
|
||||
{
|
||||
_proxy = proxy;
|
||||
}
|
||||
|
||||
public override string Link
|
||||
{
|
||||
get { return "https://telegram.org/"; }
|
||||
}
|
||||
|
||||
public override void OnGrab(GrabMessage grabMessage)
|
||||
{
|
||||
const string title = "Episode Grabbed";
|
||||
|
||||
_proxy.SendNotification(title, grabMessage.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnDownload(DownloadMessage message)
|
||||
{
|
||||
const string title = "Episode Downloaded";
|
||||
|
||||
_proxy.SendNotification(title, message.Message, Settings);
|
||||
}
|
||||
|
||||
public override void OnRename(Series series)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Telegram";
|
||||
}
|
||||
}
|
||||
|
||||
public override bool SupportsOnRename
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override ValidationResult Test()
|
||||
{
|
||||
var failures = new List<ValidationFailure>();
|
||||
|
||||
failures.AddIfNotNull(_proxy.Test(Settings));
|
||||
|
||||
return new ValidationResult(failures);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/NzbDrone.Core/Notifications/Telegram/TelegramError.cs
Normal file
14
src/NzbDrone.Core/Notifications/Telegram/TelegramError.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Telegram
|
||||
{
|
||||
public class TelegramError
|
||||
{
|
||||
public bool Ok { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "error_code")]
|
||||
public int ErrorCode { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
||||
72
src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs
Normal file
72
src/NzbDrone.Core/Notifications/Telegram/TelegramService.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using RestSharp;
|
||||
using NzbDrone.Core.Rest;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Telegram
|
||||
{
|
||||
public interface ITelegramProxy
|
||||
{
|
||||
void SendNotification(string title, string message, TelegramSettings settings);
|
||||
ValidationFailure Test(TelegramSettings settings);
|
||||
}
|
||||
|
||||
public class TelegramProxy : ITelegramProxy
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private const string URL = "https://api.telegram.org";
|
||||
|
||||
public TelegramProxy(Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void SendNotification(string title, string message, TelegramSettings settings)
|
||||
{
|
||||
//Format text to add the title before and bold using markdown
|
||||
var text = $"*{title}*\n{message}";
|
||||
var client = RestClientFactory.BuildClient(URL);
|
||||
var request = new RestRequest("bot{token}/sendmessage", Method.POST);
|
||||
|
||||
request.AddUrlSegment("token", settings.BotToken);
|
||||
request.AddParameter("chat_id", settings.ChatId);
|
||||
request.AddParameter("parse_mode", "Markdown");
|
||||
request.AddParameter("text", text);
|
||||
|
||||
client.ExecuteAndValidate(request);
|
||||
}
|
||||
|
||||
public ValidationFailure Test(TelegramSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
const string title = "Test Notification";
|
||||
const string body = "This is a test message from Sonarr";
|
||||
|
||||
SendNotification(title, body, settings);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to send test message: " + ex.Message);
|
||||
|
||||
var restException = ex as RestException;
|
||||
|
||||
if (restException != null && restException.Response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
var error = Json.Deserialize<TelegramError>(restException.Response.Content);
|
||||
var property = error.Description.ContainsIgnoreCase("chat not found") ? "ChatId" : "BotToken";
|
||||
|
||||
return new ValidationFailure(property, error.Description);
|
||||
}
|
||||
|
||||
return new ValidationFailure("BotToken", "Unable to send test message");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs
Normal file
40
src/NzbDrone.Core/Notifications/Telegram/TelegramSettings.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Notifications.Telegram
|
||||
{
|
||||
public class TelegramSettingsValidator : AbstractValidator<TelegramSettings>
|
||||
{
|
||||
public TelegramSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.BotToken).NotEmpty();
|
||||
RuleFor(c => c.ChatId).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class TelegramSettings : IProviderConfig
|
||||
{
|
||||
private static readonly TelegramSettingsValidator Validator = new TelegramSettingsValidator();
|
||||
|
||||
[FieldDefinition(0, Label = "Bot Token", HelpLink = "https://core.telegram.org/bots")]
|
||||
public string BotToken { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Chat ID", HelpLink = "http://stackoverflow.com/a/37396871/882971", HelpText = "You must start a conversation with the bot or add it to your group to receive messages")]
|
||||
public string ChatId { get; set; }
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(ChatId) && !string.IsNullOrWhiteSpace(BotToken);
|
||||
}
|
||||
}
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -829,6 +829,7 @@
|
||||
<Compile Include="Notifications\Plex\PlexAuthenticationException.cs" />
|
||||
<Compile Include="Notifications\CustomScript\CustomScript.cs" />
|
||||
<Compile Include="Notifications\CustomScript\CustomScriptSettings.cs" />
|
||||
<Compile Include="Notifications\Plex\PlexVersionException.cs" />
|
||||
<Compile Include="Notifications\Plex\PlexHomeTheater.cs" />
|
||||
<Compile Include="Notifications\Plex\PlexHomeTheaterSettings.cs" />
|
||||
<Compile Include="Notifications\Plex\PlexClientService.cs" />
|
||||
@@ -842,6 +843,10 @@
|
||||
<Compile Include="Notifications\Synology\SynologyIndexer.cs" />
|
||||
<Compile Include="Notifications\Synology\SynologyIndexerProxy.cs" />
|
||||
<Compile Include="Notifications\Synology\SynologyIndexerSettings.cs" />
|
||||
<Compile Include="Notifications\Telegram\InvalidResponseException.cs" />
|
||||
<Compile Include="Notifications\Telegram\Telegram.cs" />
|
||||
<Compile Include="Notifications\Telegram\TelegramService.cs" />
|
||||
<Compile Include="Notifications\Telegram\TelegramSettings.cs" />
|
||||
<Compile Include="Notifications\Twitter\OAuthToken.cs" />
|
||||
<Compile Include="Notifications\Twitter\TwitterException.cs" />
|
||||
<Compile Include="Notifications\Webhook\WebhookEpisode.cs" />
|
||||
@@ -1173,6 +1178,7 @@
|
||||
<Link>libsqlite3.0.dylib</Link>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Compile Include="Notifications\Telegram\TelegramError.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@@ -470,6 +470,10 @@ namespace NzbDrone.Core.Organizer
|
||||
}
|
||||
break;
|
||||
|
||||
case "MPEG-2 Video":
|
||||
videoCodec = "MPEG2";
|
||||
break;
|
||||
|
||||
default:
|
||||
videoCodec = episodeFile.MediaInfo.VideoCodec;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user