mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-10 04:52:42 +01:00
Fixed: Plex server authentication
This commit is contained in:
parent
af75813347
commit
5bc820efed
@ -33,79 +33,6 @@ public void Setup()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetSectionKeys_should_return_single_section_key_when_only_one_show_section()
|
|
||||||
{
|
|
||||||
var response = "<MediaContainer size=\"1\" mediaTagPrefix=\"/system/bundle/media/flags/\" mediaTagVersion=\"1329809559\" title1=\"Plex Library\" identifier=\"com.plexapp.plugins.library\"><Directory refreshing=\"0\" key=\"5\" type=\"show\" title=\"TV Shows\" art=\"/:/resources/show-fanart.jpg\" agent=\"com.plexapp.agents.thetvdb\" scanner=\"Plex Series Scanner\" language=\"en\" updatedAt=\"1329810350\"><Location path=\"C:/Test/TV\"/></Directory></MediaContainer>";
|
|
||||||
Stream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(response));
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
|
||||||
.Returns(stream);
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<PlexService>().GetSectionKeys(new PlexServerSettings { Host = "localhost", Port = 32400 });
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
|
||||||
result.First().Should().Be(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetSectionKeys_should_return_single_section_key_when_only_one_show_section_with_other_sections()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var response = "<MediaContainer size=\"1\" mediaTagPrefix=\"/system/bundle/media/flags/\" mediaTagVersion=\"1329809559\" title1=\"Plex Library\" identifier=\"com.plexapp.plugins.library\"><Directory refreshing=\"0\" key=\"5\" type=\"show\" title=\"TV Shows\" art=\"/:/resources/show-fanart.jpg\" agent=\"com.plexapp.agents.thetvdb\" scanner=\"Plex Series Scanner\" language=\"en\" updatedAt=\"1329810350\"><Location path=\"C:/Test/TV\"/></Directory><Directory refreshing=\"0\" key=\"7\" type=\"movie\" title=\"TV Shows\" art=\"/:/resources/show-fanart.jpg\" agent=\"com.plexapp.agents.thetvdb\" scanner=\"Plex Series Scanner\" language=\"en\" updatedAt=\"1329810350\"><Location path=\"C:/Test/TV\"/></Directory></MediaContainer>";
|
|
||||||
Stream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(response));
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
|
||||||
.Returns(stream);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<PlexService>().GetSectionKeys(new PlexServerSettings { Host = "localhost", Port = 32400 });
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(1);
|
|
||||||
result.First().Should().Be(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void GetSectionKeys_should_return_multiple_section_keys_when_there_are_multiple_show_sections()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var response = "<MediaContainer size=\"1\" mediaTagPrefix=\"/system/bundle/media/flags/\" mediaTagVersion=\"1329809559\" title1=\"Plex Library\" identifier=\"com.plexapp.plugins.library\"><Directory refreshing=\"0\" key=\"5\" type=\"show\" title=\"TV Shows\" art=\"/:/resources/show-fanart.jpg\" agent=\"com.plexapp.agents.thetvdb\" scanner=\"Plex Series Scanner\" language=\"en\" updatedAt=\"1329810350\"><Location path=\"C:/Test/TV\"/></Directory><Directory refreshing=\"0\" key=\"6\" type=\"show\" title=\"TV Shows\" art=\"/:/resources/show-fanart.jpg\" agent=\"com.plexapp.agents.thetvdb\" scanner=\"Plex Series Scanner\" language=\"en\" updatedAt=\"1329810350\"><Location path=\"C:/Test/TV\"/></Directory></MediaContainer>";
|
|
||||||
Stream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(response));
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadStream("http://localhost:32400/library/sections", null))
|
|
||||||
.Returns(stream);
|
|
||||||
|
|
||||||
|
|
||||||
var result = Mocker.Resolve<PlexService>().GetSectionKeys(new PlexServerSettings { Host = "localhost", Port = 32400 });
|
|
||||||
|
|
||||||
|
|
||||||
result.Should().HaveCount(2);
|
|
||||||
result.First().Should().Be(5);
|
|
||||||
result.Last().Should().Be(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void UpdateSection_should_update_section()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
var response = "";
|
|
||||||
Stream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(response));
|
|
||||||
|
|
||||||
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString("http://localhost:32400/library/sections/5/refresh"))
|
|
||||||
.Returns(response);
|
|
||||||
|
|
||||||
|
|
||||||
Mocker.Resolve<PlexService>().UpdateSection(new PlexServerSettings { Host = "localhost", Port = 32400 }, 5);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Notify_should_send_notification()
|
public void Notify_should_send_notification()
|
||||||
{
|
{
|
||||||
|
9
src/NzbDrone.Core/Notifications/Plex/PlexError.cs
Normal file
9
src/NzbDrone.Core/Notifications/Plex/PlexError.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public class PlexError
|
||||||
|
{
|
||||||
|
public String Error { get; set; }
|
||||||
|
}
|
||||||
|
}
|
19
src/NzbDrone.Core/Notifications/Plex/PlexException.cs
Normal file
19
src/NzbDrone.Core/Notifications/Plex/PlexException.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NzbDrone.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public class PlexException : NzbDroneException
|
||||||
|
{
|
||||||
|
public PlexException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlexException(string message, params object[] args) : base(message, args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/NzbDrone.Core/Notifications/Plex/PlexSection.cs
Normal file
26
src/NzbDrone.Core/Notifications/Plex/PlexSection.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public class PlexSection
|
||||||
|
{
|
||||||
|
public Int32 Id { get; set; }
|
||||||
|
public String Path { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlexDirectory
|
||||||
|
{
|
||||||
|
public String Type { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("_children")]
|
||||||
|
public List<PlexSection> Sections { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlexMediaContainer
|
||||||
|
{
|
||||||
|
[JsonProperty("_children")]
|
||||||
|
public List<PlexDirectory> Directories { get; set; }
|
||||||
|
}
|
||||||
|
}
|
121
src/NzbDrone.Core/Notifications/Plex/PlexServerProxy.cs
Normal file
121
src/NzbDrone.Core/Notifications/Plex/PlexServerProxy.cs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using RestSharp;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public interface IPlexServerProxy
|
||||||
|
{
|
||||||
|
List<PlexSection> GetTvSections(PlexServerSettings settings);
|
||||||
|
void Update(int sectionId, PlexServerSettings settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlexServerProxy : IPlexServerProxy
|
||||||
|
{
|
||||||
|
private readonly ICached<String> _authCache;
|
||||||
|
|
||||||
|
public PlexServerProxy(ICacheManager cacheManager)
|
||||||
|
{
|
||||||
|
_authCache = cacheManager.GetCache<String>(GetType(), "authCache");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PlexSection> GetTvSections(PlexServerSettings settings)
|
||||||
|
{
|
||||||
|
var request = GetPlexServerRequest("library/sections", Method.GET, settings);
|
||||||
|
var client = GetPlexServerClient(settings);
|
||||||
|
|
||||||
|
var response = client.Execute(request);
|
||||||
|
|
||||||
|
return Json.Deserialize<PlexMediaContainer>(response.Content)
|
||||||
|
.Directories
|
||||||
|
.Where(d => d.Type == "show")
|
||||||
|
.SelectMany(d => d.Sections)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(int sectionId, PlexServerSettings settings)
|
||||||
|
{
|
||||||
|
var resource = String.Format("library/sections/{2}/refresh");
|
||||||
|
var request = GetPlexServerRequest(resource, Method.GET, settings);
|
||||||
|
var client = GetPlexServerClient(settings);
|
||||||
|
|
||||||
|
var response = client.Execute(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String Authenticate(string username, string password)
|
||||||
|
{
|
||||||
|
var request = GetMyPlexRequest("users/sign_in.json", Method.POST);
|
||||||
|
var client = GetMyPlexClient(username, password);
|
||||||
|
|
||||||
|
var response = client.Execute(request);
|
||||||
|
CheckForError(response.Content);
|
||||||
|
|
||||||
|
var user = Json.Deserialize<PlexUser>(JObject.Parse(response.Content).SelectToken("user").ToString());
|
||||||
|
|
||||||
|
_authCache.Set(username, user.AuthenticationToken);
|
||||||
|
|
||||||
|
return user.AuthenticationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestClient GetMyPlexClient(string username, string password)
|
||||||
|
{
|
||||||
|
var client = new RestClient("https://my.plexapp.com");
|
||||||
|
client.Authenticator = new HttpBasicAuthenticator(username, password);
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestRequest GetMyPlexRequest(string resource, Method method)
|
||||||
|
{
|
||||||
|
var request = new RestRequest(resource, method);
|
||||||
|
request.AddHeader("X-Plex-Platform", "Windows");
|
||||||
|
request.AddHeader("X-Plex-Platform-Version", "7");
|
||||||
|
request.AddHeader("X-Plex-Provides", "player");
|
||||||
|
request.AddHeader("X-Plex-Client-Identifier", "AB6CCCC7-5CF5-4523-826A-B969E0FFD8A0");
|
||||||
|
request.AddHeader("X-Plex-Product", "PlexWMC");
|
||||||
|
request.AddHeader("X-Plex-Version", "0");
|
||||||
|
|
||||||
|
return request;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestClient GetPlexServerClient(PlexServerSettings settings)
|
||||||
|
{
|
||||||
|
return new RestClient(String.Format("http://{0}:{1}", settings.Host, settings.Port));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestRequest GetPlexServerRequest(string resource, Method method, PlexServerSettings settings)
|
||||||
|
{
|
||||||
|
var request = new RestRequest(resource, method);
|
||||||
|
request.AddHeader("Accept", "application/json");
|
||||||
|
|
||||||
|
if (!settings.Username.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
request.AddParameter("X-Plex-Token", GetAuthenticationToken(settings.Username, settings.Password));
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAuthenticationToken(string username, string password)
|
||||||
|
{
|
||||||
|
return _authCache.Get(username, () => Authenticate(username, password));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckForError(string response)
|
||||||
|
{
|
||||||
|
var error = Json.Deserialize<PlexError>(response);
|
||||||
|
|
||||||
|
if (error != null && !error.Error.IsNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
throw new PlexException(error.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ public PlexServerSettings()
|
|||||||
[FieldDefinition(2, Label = "Username")]
|
[FieldDefinition(2, Label = "Username")]
|
||||||
public String Username { get; set; }
|
public String Username { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(3, Label = "Password")]
|
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
|
||||||
public String Password { get; set; }
|
public String Password { get; set; }
|
||||||
|
|
||||||
[FieldDefinition(4, Label = "Update Library", Type = FieldType.Checkbox)]
|
[FieldDefinition(4, Label = "Update Library", Type = FieldType.Checkbox)]
|
||||||
|
@ -18,11 +18,13 @@ public interface IPlexService
|
|||||||
public class PlexService : IPlexService, IExecute<TestPlexClientCommand>, IExecute<TestPlexServerCommand>
|
public class PlexService : IPlexService, IExecute<TestPlexClientCommand>, IExecute<TestPlexServerCommand>
|
||||||
{
|
{
|
||||||
private readonly IHttpProvider _httpProvider;
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly IPlexServerProxy _plexServerProxy;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public PlexService(IHttpProvider httpProvider, Logger logger)
|
public PlexService(IHttpProvider httpProvider, IPlexServerProxy plexServerProxy, Logger logger)
|
||||||
{
|
{
|
||||||
_httpProvider = httpProvider;
|
_httpProvider = httpProvider;
|
||||||
|
_plexServerProxy = plexServerProxy;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +47,7 @@ public void UpdateLibrary(PlexServerSettings settings)
|
|||||||
{
|
{
|
||||||
_logger.Debug("Sending Update Request to Plex Server");
|
_logger.Debug("Sending Update Request to Plex Server");
|
||||||
var sections = GetSectionKeys(settings);
|
var sections = GetSectionKeys(settings);
|
||||||
sections.ForEach(s => UpdateSection(settings, s));
|
sections.ForEach(s => UpdateSection(s, settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
@ -55,26 +57,21 @@ public void UpdateLibrary(PlexServerSettings settings)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<int> GetSectionKeys(PlexServerSettings settings)
|
private List<int> GetSectionKeys(PlexServerSettings settings)
|
||||||
{
|
{
|
||||||
_logger.Debug("Getting sections from Plex host: {0}", settings.Host);
|
_logger.Debug("Getting sections from Plex host: {0}", settings.Host);
|
||||||
var url = String.Format("http://{0}:{1}/library/sections", settings.Host, settings.Port);
|
|
||||||
var xmlStream = _httpProvider.DownloadStream(url, GetCredentials(settings));
|
|
||||||
var xDoc = XDocument.Load(xmlStream);
|
|
||||||
var mediaContainer = xDoc.Descendants("MediaContainer").FirstOrDefault();
|
|
||||||
var directories = mediaContainer.Descendants("Directory").Where(x => x.Attribute("type").Value == "show");
|
|
||||||
|
|
||||||
return directories.Select(d => Int32.Parse(d.Attribute("key").Value)).ToList();
|
return _plexServerProxy.GetTvSections(settings).Select(s => s.Id).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSection(PlexServerSettings settings, int key)
|
private void UpdateSection(int key, PlexServerSettings settings)
|
||||||
{
|
{
|
||||||
_logger.Debug("Updating Plex host: {0}, Section: {1}", settings.Host, key);
|
_logger.Debug("Updating Plex host: {0}, Section: {1}", settings.Host, key);
|
||||||
var url = String.Format("http://{0}:{1}/library/sections/{2}/refresh", settings.Host, settings.Port, key);
|
|
||||||
_httpProvider.DownloadString(url, GetCredentials(settings));
|
_plexServerProxy.Update(key, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SendCommand(string host, int port, string command, string username, string password)
|
private string SendCommand(string host, int port, string command, string username, string password)
|
||||||
{
|
{
|
||||||
var url = String.Format("http://{0}:{1}/xbmcCmds/xbmcHttp?command={2}", host, port, command);
|
var url = String.Format("http://{0}:{1}/xbmcCmds/xbmcHttp?command={2}", host, port, command);
|
||||||
|
|
||||||
@ -86,13 +83,6 @@ public string SendCommand(string host, int port, string command, string username
|
|||||||
return _httpProvider.DownloadString(url);
|
return _httpProvider.DownloadString(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NetworkCredential GetCredentials(PlexServerSettings settings)
|
|
||||||
{
|
|
||||||
if (settings.Username.IsNullOrWhiteSpace()) return null;
|
|
||||||
|
|
||||||
return new NetworkCredential(settings.Username, settings.Password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Execute(TestPlexClientCommand message)
|
public void Execute(TestPlexClientCommand message)
|
||||||
{
|
{
|
||||||
_logger.Debug("Sending Test Notifcation to Plex Client: {0}", message.Host);
|
_logger.Debug("Sending Test Notifcation to Plex Client: {0}", message.Host);
|
||||||
|
11
src/NzbDrone.Core/Notifications/Plex/PlexUser.cs
Normal file
11
src/NzbDrone.Core/Notifications/Plex/PlexUser.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Notifications.Plex
|
||||||
|
{
|
||||||
|
public class PlexUser
|
||||||
|
{
|
||||||
|
[JsonProperty("authentication_token")]
|
||||||
|
public String AuthenticationToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -377,6 +377,11 @@
|
|||||||
<Compile Include="Notifications\NotificationFactory.cs" />
|
<Compile Include="Notifications\NotificationFactory.cs" />
|
||||||
<Compile Include="Notifications\NotificationService.cs" />
|
<Compile Include="Notifications\NotificationService.cs" />
|
||||||
<Compile Include="Notifications\DownloadMessage.cs" />
|
<Compile Include="Notifications\DownloadMessage.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\PlexError.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\PlexException.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\PlexSection.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\PlexServerProxy.cs" />
|
||||||
|
<Compile Include="Notifications\Plex\PlexUser.cs" />
|
||||||
<Compile Include="Notifications\PushBullet\PushBullet.cs" />
|
<Compile Include="Notifications\PushBullet\PushBullet.cs" />
|
||||||
<Compile Include="Notifications\PushBullet\PushBulletProxy.cs" />
|
<Compile Include="Notifications\PushBullet\PushBulletProxy.cs" />
|
||||||
<Compile Include="Notifications\PushBullet\PushBulletSettings.cs" />
|
<Compile Include="Notifications\PushBullet\PushBulletSettings.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user