mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-05-02 12:49:07 -05:00
added plex plugin
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
namespace FileFlows.Plex;
|
||||
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
public static string? EmptyAsNull(this string str) => str == string.Empty ? null : str;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
global using System;
|
||||
global using System.Text;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using FileFlows.Plugin;
|
||||
global using FileFlows.Plugin.Attributes;
|
||||
@@ -0,0 +1,119 @@
|
||||
using FileFlows.Plex.Models;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FileFlows.Plex.MediaManagement;
|
||||
|
||||
public class PlexUpdater: Node
|
||||
{
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 2;
|
||||
public override FlowElementType Type => FlowElementType.Process;
|
||||
public override string Icon => "fas fa-paper-plane";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var settings = args.GetPluginSettings<PluginSettings>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(settings?.AccessToken))
|
||||
{
|
||||
args.Logger?.WLog("No access token set");
|
||||
return 2;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(settings?.ServerUrl))
|
||||
{
|
||||
args.Logger?.WLog("No server URL set");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// get the path
|
||||
string path = args.WorkingFile;
|
||||
path = args.UnMapPath(path);
|
||||
if (args.IsDirectory == false)
|
||||
{
|
||||
bool windows = path.StartsWith("\\") || Regex.IsMatch(path, @"^[a-zA-Z]:\\");
|
||||
string pathSeparator = windows ? "\\" : "/";
|
||||
path = path.Substring(0, path.LastIndexOf(pathSeparator));
|
||||
}
|
||||
|
||||
string url = settings.ServerUrl;
|
||||
if (url.EndsWith("/") == false)
|
||||
url += "/";
|
||||
url += "library/sections";
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
var sectionsResponse= GetWebRequest(httpClient, url + "?X-Plex-Token=" + settings.AccessToken);
|
||||
if (sectionsResponse.success == false)
|
||||
{
|
||||
args.Logger?.WLog("Failed to retrieve sections" + (string.IsNullOrWhiteSpace(sectionsResponse.body) ? "" : ": " + sectionsResponse.body));
|
||||
return 2;
|
||||
}
|
||||
|
||||
PlexSections sections;
|
||||
try
|
||||
{
|
||||
var options = new System.Text.Json.JsonSerializerOptions();
|
||||
options.PropertyNameCaseInsensitive = true;
|
||||
sections = System.Text.Json.JsonSerializer.Deserialize<PlexSections>(sectionsResponse.body, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger?.ELog("Failed deserializing sections json: " + ex.Message);
|
||||
return 2;
|
||||
}
|
||||
string pathLower = path.ToLower();
|
||||
var section = sections?.MediaContainer?.Directory?.Where(x => {
|
||||
if (x.Location?.Any() != true)
|
||||
return false;
|
||||
foreach (var loc in x.Location) {
|
||||
if (loc.Path == null)
|
||||
continue;
|
||||
if (pathLower.StartsWith(loc.Path.ToLower()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).FirstOrDefault();
|
||||
if(section == null)
|
||||
{
|
||||
args.Logger?.WLog("Failed to find Plex section for path: " + path);
|
||||
return 2;
|
||||
}
|
||||
|
||||
url += $"/{section.Key}/refresh?path={Uri.EscapeDataString(path)}&X-Plex-Token=" + settings.AccessToken;
|
||||
|
||||
var updateResponse = GetWebRequest(httpClient, url);
|
||||
if (updateResponse.success == false)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(updateResponse.body) == false)
|
||||
args.Logger.WLog("Failed to update Plex:" + updateResponse.body);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private Func<HttpClient, string, (bool success, string body)> _GetWebRequest;
|
||||
internal Func<HttpClient, string, (bool success, string body)> GetWebRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_GetWebRequest == null)
|
||||
{
|
||||
_GetWebRequest = (HttpClient client, string url) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||
var response = client.GetAsync(url).Result;
|
||||
string body = response.Content.ReadAsStringAsync().Result;
|
||||
return (response.IsSuccessStatusCode, body);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
return (false, ex.Message);
|
||||
}
|
||||
};
|
||||
}
|
||||
return _GetWebRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace FileFlows.Plex.Models;
|
||||
|
||||
internal class PlexDirectory
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public PlexDirectoryLocation[] Location { get; set; }
|
||||
}
|
||||
|
||||
public class PlexDirectoryLocation
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace FileFlows.Plex.Models;
|
||||
|
||||
internal class PlexSections
|
||||
{
|
||||
public PlexSection MediaContainer { get; set; }
|
||||
}
|
||||
|
||||
internal class PlexSection
|
||||
{
|
||||
public int Size { get; set; }
|
||||
public PlexDirectory[] Directory { get; set; }
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"Plugins": {
|
||||
"Plex": {
|
||||
"Description": "A plugin that allows you to communicate with Plex.",
|
||||
"Fields": {
|
||||
"ServerUrl": "Server",
|
||||
"ServerUrl-Placeholder": "http://localhost:32400/",
|
||||
"ServerUrl-Help": "The URL of the Plex server",
|
||||
"AccessToken": "Access Token",
|
||||
"AccessToken-Help": "The access token used to communicate with the Plex server.\nhttps://github.com/revenz/Fenrus/wiki/Plex-Token"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Flow": {
|
||||
"Parts": {
|
||||
"PlexUpdater": {
|
||||
"Outputs": {
|
||||
"1": "Plex update request sent",
|
||||
"2": "Plex update request failed to send"
|
||||
},
|
||||
"Description": "Sends a message to a Plex server to update the library."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace FileFlows.Plex;
|
||||
|
||||
public class Plugin : FileFlows.Plugin.IPlugin
|
||||
{
|
||||
public string Name => "Plex";
|
||||
public string MinimumVersion => "0.5.2.690";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace FileFlows.Plex
|
||||
{
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class PluginSettings:IPluginSettings
|
||||
{
|
||||
[Text(1)]
|
||||
[Required]
|
||||
public string ServerUrl { get; set; }
|
||||
|
||||
[Text(2)]
|
||||
[Required]
|
||||
public string AccessToken { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#if(DEBUG)
|
||||
|
||||
using FileFlows.Plex.Media;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace FileFlows.Plex.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class PlexTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Plex_Basic()
|
||||
{
|
||||
var args = new NodeParameters(@"/media/movies/The Batman (2022)/The Batman.mkv", new TestLogger(), false, string.Empty);
|
||||
args.GetPluginSettingsJson = (string input) =>
|
||||
{
|
||||
return File.ReadAllText("../../../settings.json");
|
||||
};
|
||||
|
||||
var node = new PlexUpdater();
|
||||
Assert.AreEqual(1, node.Execute(args));
|
||||
}
|
||||
[TestMethod]
|
||||
public void Plex_Fail()
|
||||
{
|
||||
var args = new NodeParameters(@"/media/unknownmovies/The Batman (2022)/The Batman.mkv", new TestLogger(), false, string.Empty);
|
||||
args.GetPluginSettingsJson = (string input) =>
|
||||
{
|
||||
return File.ReadAllText("../../../settings.json");
|
||||
};
|
||||
|
||||
var node = new PlexUpdater();
|
||||
Assert.AreEqual(2, node.Execute(args));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#if(DEBUG)
|
||||
|
||||
namespace FileFlows.Plex.Tests;
|
||||
|
||||
using FileFlows.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
internal class TestLogger : ILogger
|
||||
{
|
||||
private List<string> Messages = new List<string>();
|
||||
|
||||
public void DLog(params object[] args) => Log("DBUG", args);
|
||||
|
||||
public void ELog(params object[] args) => Log("ERRR", args);
|
||||
|
||||
public void ILog(params object[] args) => Log("INFO", args);
|
||||
|
||||
public void WLog(params object[] args) => Log("WARN", args);
|
||||
private void Log(string type, object[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
string message = type + " -> " +
|
||||
string.Join(", ", args.Select(x =>
|
||||
x == null ? "null" :
|
||||
x.GetType().IsPrimitive || x is string ? x.ToString() :
|
||||
System.Text.Json.JsonSerializer.Serialize(x)));
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
public bool Contains(string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return false;
|
||||
|
||||
string log = string.Join(Environment.NewLine, Messages);
|
||||
return log.Contains(message);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Join(Environment.NewLine, this.Messages.ToArray());
|
||||
}
|
||||
|
||||
public string GetTail(int length = 50)
|
||||
{
|
||||
if (length <= 0)
|
||||
length = 50;
|
||||
if (Messages.Count <= length)
|
||||
return string.Join(Environment.NewLine, Messages);
|
||||
return string.Join(Environment.NewLine, Messages.TakeLast(length));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user